diff --git a/.gitignore b/.gitignore index 1b2d9f4c54..7bd1c8ad07 100644 --- a/.gitignore +++ b/.gitignore @@ -25,10 +25,8 @@ test/data/sql/ .vscode .gitignore .DS_Store -vendor/ docker .docker-sync -composer.lock CodeSniffer.conf test/runtime test/runtime/* diff --git a/lib/composer.json b/lib/composer.json new file mode 100644 index 0000000000..0ff71b7810 --- /dev/null +++ b/lib/composer.json @@ -0,0 +1,28 @@ +{ + "require": { + "box/spout": "2.7.3", + "dragonmantank/cron-expression": "2.3.1", + "erusev/parsedown": "1.7.4", + "ezyang/htmlpurifier": "4.18.0", + "gorhill/php-fine-diff": "0.1.0", + "gregwar/captcha": "1.3.0", + "laminas/laminas-escaper": "2.6.1", + "laminas/laminas-zendframework-bridge": "1.1.1", + "markbaker/complex": "1.5.0", + "markbaker/matrix": "1.2.3", + "masterexploder/phpthumb": "2.1", + "mobiledetect/mobiledetectlib": "2.8.45", + "mustangostang/spyc": "0.6.3", + "overtrue/pinyin": "4.0.5", + "paragonie/constant_time_encoding": "2.7.0", + "paragonie/random_compat": "9.99.100", + "pclzip/pclzip": "2.8.2", + "phpmailer/phpmailer": "6.10.0", + "phpoffice/phpspreadsheet": "1.8.2", + "phpoffice/phpword": "0.18.3", + "phpseclib/phpseclib": "3.0.46", + "psr/simple-cache": "1.0.1", + "rmccue/requests": "2.0.15", + "symfony/finder": "3.4.47" + } +} diff --git a/lib/composer.lock b/lib/composer.lock new file mode 100644 index 0000000000..6fa07346c3 --- /dev/null +++ b/lib/composer.lock @@ -0,0 +1,1639 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "015cfb3cc9d9463368148dbf304c65c9", + "packages": [ + { + "name": "box/spout", + "version": "v2.7.3", + "source": { + "type": "git", + "url": "https://github.com/box/spout.git", + "reference": "3681a3421a868ab9a65da156c554f756541f452b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/box/spout/zipball/3681a3421a868ab9a65da156c554f756541f452b", + "reference": "3681a3421a868ab9a65da156c554f756541f452b", + "shasum": "" + }, + "require": { + "ext-xmlreader": "*", + "ext-zip": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.0" + }, + "suggest": { + "ext-iconv": "To handle non UTF-8 CSV files (if \"php-intl\" is not already installed or is too limited)", + "ext-intl": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Box\\Spout\\": "src/Spout" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Adrien Loison", + "email": "adrien@box.com" + } + ], + "description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way", + "homepage": "https://www.github.com/box/spout", + "keywords": [ + "OOXML", + "csv", + "excel", + "memory", + "odf", + "ods", + "office", + "open", + "php", + "read", + "scale", + "spreadsheet", + "stream", + "write", + "xlsx" + ], + "support": { + "issues": "https://github.com/box/spout/issues", + "source": "https://github.com/box/spout/tree/v2.7.3" + }, + "abandoned": true, + "time": "2017-09-25T19:44:35+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/65b2d8ee1f10915efb3b55597da3404f096acba2", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2020-10-13T00:52:37+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.18.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0" + }, + "time": "2024-11-01T03:51:45+00:00" + }, + { + "name": "gorhill/php-fine-diff", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/falk-graeser/PHP-FineDiff.git", + "reference": "b0c9ab136958882c501d461b0ad204f908e19392" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/falk-graeser/PHP-FineDiff/zipball/b0c9ab136958882c501d461b0ad204f908e19392", + "reference": "b0c9ab136958882c501d461b0ad204f908e19392", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "GorHill\\FineDiff\\": "GorHill/FineDiff" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raymond Hill", + "email": "r.michael@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "Developer" + }, + { + "name": "Falk Gräser", + "email": "f.graeser@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "The-Clean-Up-Guy" + } + ], + "homepage": "http://www.raymondhill.net/finediff/", + "keywords": [ + "finediff" + ], + "support": { + "source": "https://github.com/falk-graeser/PHP-FineDiff/tree/0.1.0" + }, + "time": "2015-07-30T10:21:26+00:00" + }, + { + "name": "gregwar/captcha", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Captcha.git", + "reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4edbcd09fde4353b94ce550f43460eba73baf2cc", + "reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-mbstring": "*", + "php": ">=5.3.0", + "symfony/finder": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Gregwar\\": "src/Gregwar" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "description": "Captcha generator", + "homepage": "https://github.com/Gregwar/Captcha", + "keywords": [ + "bot", + "captcha", + "spam" + ], + "support": { + "issues": "https://github.com/Gregwar/Captcha/issues", + "source": "https://github.com/Gregwar/Captcha/tree/v1.3.0" + }, + "time": "2025-06-23T12:25:54+00:00" + }, + { + "name": "laminas/laminas-escaper", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "25f2a053eadfa92ddacb609dcbbc39362610da70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/25f2a053eadfa92ddacb609dcbbc39362610da70", + "reference": "25f2a053eadfa92ddacb609dcbbc39362610da70", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^5.6 || ^7.0" + }, + "replace": { + "zendframework/zend-escaper": "self.version" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev", + "dev-develop": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "time": "2019-12-31T16:43:30+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": true, + "time": "2020-09-14T14:23:00+00:00" + }, + { + "name": "markbaker/complex", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/c3131244e29c08d44fefb49e0dd35021e9e39dd2", + "reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2", + "shasum": "" + }, + "require": { + "php": "^5.6.0|^7.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0|^5.0|^6.0|^7.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0", + "sebastian/phpcpd": "2.*", + "squizlabs/php_codesniffer": "^3.4.0" + }, + "type": "library", + "autoload": { + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ], + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/1.5.0" + }, + "time": "2020-08-26T19:47:57+00:00" + }, + { + "name": "markbaker/matrix", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/44bb1ab01811116f01fe216ab37d921dccc6c10d", + "reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d", + "shasum": "" + }, + "require": { + "php": "^5.6.0|^7.0.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "dev-master", + "phploc/phploc": "^4", + "phpmd/phpmd": "dev-master", + "phpunit/phpunit": "^5.7|^6.0|7.0", + "sebastian/phpcpd": "^3.0", + "squizlabs/php_codesniffer": "^3.0@dev" + }, + "type": "library", + "autoload": { + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ], + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/1.2.3" + }, + "time": "2021-01-26T14:36:01+00:00" + }, + { + "name": "masterexploder/phpthumb", + "version": "2.1", + "source": { + "type": "git", + "url": "https://github.com/masterexploder/PHPThumb.git", + "reference": "01f6aa65aa3d136e175f67da2b4ea3e316770d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/masterexploder/PHPThumb/zipball/01f6aa65aa3d136e175f67da2b4ea3e316770d02", + "reference": "01f6aa65aa3d136e175f67da2b4ea3e316770d02", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "PHPThumb": "src", + "PHPThumb\\Tests": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jarrod Nettles", + "email": "jarrod.nettles@icloud.com" + }, + { + "name": "Ian Selby", + "email": "ian@gxdlabs.com" + } + ], + "description": "A library for manipulating images in PHP.", + "homepage": "https://github.com/masterexploder/PHPThumb", + "keywords": [ + "image", + "resize", + "rotate" + ], + "support": { + "issues": "https://github.com/masterexploder/PHPThumb/issues", + "source": "https://github.com/masterexploder/PHPThumb/tree/2.1" + }, + "time": "2015-09-08T22:55:44+00:00" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.45", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36" + }, + "type": "library", + "autoload": { + "psr-0": { + "Detection": "namespaced/" + }, + "classmap": [ + "Mobile_Detect.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.45" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "time": "2023-11-07T21:57:25+00:00" + }, + { + "name": "mustangostang/spyc", + "version": "0.6.3", + "source": { + "type": "git", + "url": "https://github.com/mustangostang/spyc.git", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/4627c838b16550b666d15aeae1e5289dd5b77da0", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "autoload": { + "files": [ + "Spyc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "mustangostang", + "email": "vlad.andersen@gmail.com" + } + ], + "description": "A simple YAML loader/dumper class for PHP", + "homepage": "https://github.com/mustangostang/spyc/", + "keywords": [ + "spyc", + "yaml", + "yml" + ], + "support": { + "issues": "https://github.com/mustangostang/spyc/issues", + "source": "https://github.com/mustangostang/spyc/tree/0.6.3" + }, + "time": "2019-09-10T13:16:29+00:00" + }, + { + "name": "overtrue/pinyin", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/overtrue/pinyin.git", + "reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/overtrue/pinyin/zipball/94fdb3ea6eca5677afd9548111d95bedcd5a4086", + "reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/const.php" + ], + "psr-4": { + "Overtrue\\Pinyin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carlos", + "homepage": "http://github.com/overtrue" + } + ], + "description": "Chinese to pinyin translator.", + "homepage": "https://github.com/overtrue/pinyin", + "keywords": [ + "Chinese", + "Pinyin", + "cn2pinyin" + ], + "support": { + "issues": "https://github.com/overtrue/pinyin/issues", + "source": "https://github.com/overtrue/pinyin/tree/master" + }, + "time": "2019-09-20T12:43:45+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.7.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:18:48+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "pclzip/pclzip", + "version": "2.8.2", + "source": { + "type": "git", + "url": "https://github.com/ivanlanin/pclzip.git", + "reference": "19dd1de9d3f5fc4d7d70175b4c344dee329f45fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ivanlanin/pclzip/zipball/19dd1de9d3f5fc4d7d70175b4c344dee329f45fd", + "reference": "19dd1de9d3f5fc4d7d70175b4c344dee329f45fd", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "pclzip.lib.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Vincent Blavet" + } + ], + "description": "A PHP library that offers compression and extraction functions for Zip formatted archives", + "homepage": "http://www.phpconcept.net/pclzip", + "keywords": [ + "php", + "zip" + ], + "support": { + "issues": "https://github.com/ivanlanin/pclzip/issues", + "source": "https://github.com/ivanlanin/pclzip/tree/master" + }, + "time": "2014-06-05T11:42:24+00:00" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.10.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.2", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2025-04-24T15:19:31+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "0c1346a1956347590b7db09533966307d20cb7cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/0c1346a1956347590b7db09533966307d20cb7cc", + "reference": "0c1346a1956347590b7db09533966307d20cb7cc", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "markbaker/complex": "^1.4", + "markbaker/matrix": "^1.1", + "php": "^5.6|^7.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "^1.0.0", + "dompdf/dompdf": "^0.8.0", + "friendsofphp/php-cs-fixer": "@stable", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^7.0.0", + "phpcompatibility/php-compatibility": "^8.0", + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.3", + "tecnickcom/tcpdf": "^6.2" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + }, + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.8.2" + }, + "time": "2019-07-08T21:21:25+00:00" + }, + { + "name": "phpoffice/phpword", + "version": "0.18.3", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PHPWord.git", + "reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/be0190cd5d8f95b4be08d5853b107aa4e352759a", + "reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "laminas/laminas-escaper": "^2.2", + "php": "^5.3.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "dompdf/dompdf": "0.8.* || 1.0.*", + "ext-gd": "*", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^2.2", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", + "php-coveralls/php-coveralls": "1.1.0 || ^2.0", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^4.8.36 || ^7.0", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", + "tecnickcom/tcpdf": "6.*" + }, + "suggest": { + "dompdf/dompdf": "Allows writing PDF", + "ext-gd2": "Allows adding images", + "ext-xmlwriter": "Allows writing OOXML and ODF", + "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", + "ext-zip": "Allows writing OOXML and ODF" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.19-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOffice\\PhpWord\\": "src/PhpWord" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Mark Baker" + }, + { + "name": "Gabriel Bull", + "email": "me@gabrielbull.com", + "homepage": "http://gabrielbull.com/" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net/blog/" + }, + { + "name": "Ivan Lanin", + "homepage": "http://ivan.lanin.org" + }, + { + "name": "Roman Syroeshko", + "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" + }, + { + "name": "Antoine de Troostembergh" + } + ], + "description": "PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)", + "homepage": "http://phpoffice.github.io", + "keywords": [ + "ISO IEC 29500", + "OOXML", + "Office Open XML", + "OpenDocument", + "OpenXML", + "PhpOffice", + "PhpWord", + "Rich Text Format", + "WordprocessingML", + "doc", + "docx", + "html", + "odf", + "odt", + "office", + "pdf", + "php", + "reader", + "rtf", + "template", + "template processor", + "word", + "writer" + ], + "support": { + "issues": "https://github.com/PHPOffice/PHPWord/issues", + "source": "https://github.com/PHPOffice/PHPWord/tree/0.18.3" + }, + "time": "2022-02-17T15:40:03+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.46", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2025-06-26T16:29:55+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "rmccue/requests", + "version": "v2.0.15", + "source": { + "type": "git", + "url": "https://github.com/WordPress/Requests.git", + "reference": "877cd66169755899682f1595e057334b40d9d149" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/877cd66169755899682f1595e057334b40d9d149", + "reference": "877cd66169755899682f1595e057334b40d9d149", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "php-parallel-lint/php-console-highlighter": "^0.5.0", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "requests/test-server": "dev-main", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6", + "wp-coding-standards/wpcs": "^2.0", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", + "ext-curl": "For improved performance", + "ext-openssl": "For secure transport support", + "ext-zlib": "For improved performance when decompressing encoded streams" + }, + "type": "library", + "autoload": { + "files": [ + "library/Deprecated.php" + ], + "psr-4": { + "WpOrg\\Requests\\": "src/" + }, + "classmap": [ + "library/Requests.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Ryan McCue", + "homepage": "https://rmccue.io/" + }, + { + "name": "Alain Schlesser", + "homepage": "https://github.com/schlessera" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl" + }, + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/Requests/graphs/contributors" + } + ], + "description": "A HTTP library written in PHP, for human beings.", + "homepage": "https://requests.ryanmccue.info/", + "keywords": [ + "curl", + "fsockopen", + "http", + "idna", + "ipv6", + "iri", + "sockets" + ], + "support": { + "docs": "https://requests.ryanmccue.info/", + "issues": "https://github.com/WordPress/Requests/issues", + "source": "https://github.com/WordPress/Requests" + }, + "time": "2025-01-21T10:13:31+00:00" + }, + { + "name": "symfony/finder", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-11-16T17:02:08+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/lib/vendor/autoload.php b/lib/vendor/autoload.php new file mode 100644 index 0000000000..58303259d8 --- /dev/null +++ b/lib/vendor/autoload.php @@ -0,0 +1,7 @@ + Performance tests status: [![Build Status](https://travis-ci.org/box/spout.svg?branch=perf-tests)](https://travis-ci.org/box/spout) + + +## Support + +You can ask questions, submit new features ideas or discuss about Spout in the chat room:
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/box/spout?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +## Copyright and License + +Copyright 2017 Box, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/vendor/box/spout/composer.json b/lib/vendor/box/spout/composer.json new file mode 100644 index 0000000000..76485c963a --- /dev/null +++ b/lib/vendor/box/spout/composer.json @@ -0,0 +1,37 @@ +{ + "name": "box/spout", + "description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way", + "type": "library", + "keywords": ["php","read","write","csv","xlsx","ods","odf","open","office","excel","spreadsheet","scale","memory","stream","ooxml"], + "license": "Apache-2.0", + "homepage": "https://www.github.com/box/spout", + "authors": [ + { + "name": "Adrien Loison", + "email": "adrien@box.com" + } + ], + "require": { + "php": ">=5.4.0", + "ext-zip": "*", + "ext-xmlreader" : "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.0" + }, + "suggest": { + "ext-iconv": "To handle non UTF-8 CSV files (if \"php-intl\" is not already installed or is too limited)", + "ext-intl": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)" + }, + "autoload": { + "psr-4": { + "Box\\Spout\\": "src/Spout" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev" + } + } + +} diff --git a/lib/vendor/box/spout/src/Spout/Autoloader/Psr4Autoloader.php b/lib/vendor/box/spout/src/Spout/Autoloader/Psr4Autoloader.php new file mode 100644 index 0000000000..67cccc376f --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Autoloader/Psr4Autoloader.php @@ -0,0 +1,150 @@ +prefixes[$prefix]) === false) { + $this->prefixes[$prefix] = array(); + } + + // retain the base directory for the namespace prefix + if ($prepend) { + array_unshift($this->prefixes[$prefix], $baseDir); + } else { + array_push($this->prefixes[$prefix], $baseDir); + } + } + + /** + * Loads the class file for a given class name. + * + * @param string $class The fully-qualified class name. + * @return mixed The mapped file name on success, or boolean false on + * failure. + */ + public function loadClass($class) + { + // the current namespace prefix + $prefix = $class; + + // work backwards through the namespace names of the fully-qualified + // class name to find a mapped file name + while (false !== $pos = strrpos($prefix, '\\')) { + + // retain the trailing namespace separator in the prefix + $prefix = substr($class, 0, $pos + 1); + + // the rest is the relative class name + $relativeClass = substr($class, $pos + 1); + + // try to load a mapped file for the prefix and relative class + $mappedFile = $this->loadMappedFile($prefix, $relativeClass); + if ($mappedFile !== false) { + return $mappedFile; + } + + // remove the trailing namespace separator for the next iteration + // of strrpos() + $prefix = rtrim($prefix, '\\'); + } + + // never found a mapped file + return false; + } + + /** + * Load the mapped file for a namespace prefix and relative class. + * + * @param string $prefix The namespace prefix. + * @param string $relativeClass The relative class name. + * @return mixed Boolean false if no mapped file can be loaded, or the + * name of the mapped file that was loaded. + */ + protected function loadMappedFile($prefix, $relativeClass) + { + // are there any base directories for this namespace prefix? + if (isset($this->prefixes[$prefix]) === false) { + return false; + } + + // look through base directories for this namespace prefix + foreach ($this->prefixes[$prefix] as $baseDir) { + + // replace the namespace prefix with the base directory, + // replace namespace separators with directory separators + // in the relative class name, append with .php + $file = $baseDir + . str_replace('\\', '/', $relativeClass) + . '.php'; + + // if the mapped file exists, require it + if ($this->requireFile($file)) { + // yes, we're done + return $file; + } + } + + // never found it + return false; + } + + /** + * If a file exists, require it from the file system. + * + * @param string $file The file to require. + * @return bool True if the file exists, false if not. + */ + protected function requireFile($file) + { + if (file_exists($file)) { + require $file; + return true; + } + return false; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Autoloader/autoload.php b/lib/vendor/box/spout/src/Spout/Autoloader/autoload.php new file mode 100644 index 0000000000..73ee519039 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Autoloader/autoload.php @@ -0,0 +1,15 @@ +register(); +$loader->addNamespace('Box\Spout', $srcBaseDirectory); diff --git a/lib/vendor/box/spout/src/Spout/Common/Escaper/CSV.php b/lib/vendor/box/spout/src/Spout/Common/Escaper/CSV.php new file mode 100644 index 0000000000..4bc2d1af61 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Escaper/CSV.php @@ -0,0 +1,38 @@ +', '&') need to be encoded. + // Single and double quotes can be left as is. + $escapedString = htmlspecialchars($string, ENT_NOQUOTES); + + // control characters values are from 0 to 1F (hex values) in the ASCII table + // some characters should not be escaped though: "\t", "\r" and "\n". + $regexPattern = '[\x00-\x08' . + // skipping "\t" (0x9) and "\n" (0xA) + '\x0B-\x0C' . + // skipping "\r" (0xD) + '\x0E-\x1F]'; + $replacedString = preg_replace("/$regexPattern/", '�', $escapedString); + } + + return $replacedString; + } + + /** + * Unescapes the given string to make it compatible with XLSX + * + * @param string $string The string to unescape + * @return string The unescaped string + */ + public function unescape($string) + { + // ============== + // = WARNING = + // ============== + // It is assumed that the given string has already had its XML entities decoded. + // This is true if the string is coming from a DOMNode (as DOMNode already decode XML entities on creation). + // Therefore there is no need to call "htmlspecialchars_decode()". + return $string; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Escaper/XLSX.php b/lib/vendor/box/spout/src/Spout/Common/Escaper/XLSX.php new file mode 100644 index 0000000000..7c6c61b37b --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Escaper/XLSX.php @@ -0,0 +1,185 @@ +escapableControlCharactersPattern = $this->getEscapableControlCharactersPattern(); + $this->controlCharactersEscapingMap = $this->getControlCharactersEscapingMap(); + $this->controlCharactersEscapingReverseMap = array_flip($this->controlCharactersEscapingMap); + } + + /** + * Escapes the given string to make it compatible with XLSX + * + * @param string $string The string to escape + * @return string The escaped string + */ + public function escape($string) + { + $escapedString = $this->escapeControlCharacters($string); + // @NOTE: Using ENT_NOQUOTES as only XML entities ('<', '>', '&') need to be encoded. + // Single and double quotes can be left as is. + $escapedString = htmlspecialchars($escapedString, ENT_NOQUOTES); + + return $escapedString; + } + + /** + * Unescapes the given string to make it compatible with XLSX + * + * @param string $string The string to unescape + * @return string The unescaped string + */ + public function unescape($string) + { + // ============== + // = WARNING = + // ============== + // It is assumed that the given string has already had its XML entities decoded. + // This is true if the string is coming from a DOMNode (as DOMNode already decode XML entities on creation). + // Therefore there is no need to call "htmlspecialchars_decode()". + $unescapedString = $this->unescapeControlCharacters($string); + + return $unescapedString; + } + + /** + * @return string Regex pattern containing all escapable control characters + */ + protected function getEscapableControlCharactersPattern() + { + // control characters values are from 0 to 1F (hex values) in the ASCII table + // some characters should not be escaped though: "\t", "\r" and "\n". + return '[\x00-\x08' . + // skipping "\t" (0x9) and "\n" (0xA) + '\x0B-\x0C' . + // skipping "\r" (0xD) + '\x0E-\x1F]'; + } + + /** + * Builds the map containing control characters to be escaped + * mapped to their escaped values. + * "\t", "\r" and "\n" don't need to be escaped. + * + * NOTE: the logic has been adapted from the XlsxWriter library (BSD License) + * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89 + * + * @return string[] + */ + protected function getControlCharactersEscapingMap() + { + $controlCharactersEscapingMap = []; + + // control characters values are from 0 to 1F (hex values) in the ASCII table + for ($charValue = 0x00; $charValue <= 0x1F; $charValue++) { + $character = chr($charValue); + if (preg_match("/{$this->escapableControlCharactersPattern}/", $character)) { + $charHexValue = dechex($charValue); + $escapedChar = '_x' . sprintf('%04s' , strtoupper($charHexValue)) . '_'; + $controlCharactersEscapingMap[$escapedChar] = $character; + } + } + + return $controlCharactersEscapingMap; + } + + /** + * Converts PHP control characters from the given string to OpenXML escaped control characters + * + * Excel escapes control characters with _xHHHH_ and also escapes any + * literal strings of that type by encoding the leading underscore. + * So "\0" -> _x0000_ and "_x0000_" -> _x005F_x0000_. + * + * NOTE: the logic has been adapted from the XlsxWriter library (BSD License) + * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89 + * + * @param string $string String to escape + * @return string + */ + protected function escapeControlCharacters($string) + { + $escapedString = $this->escapeEscapeCharacter($string); + + // if no control characters + if (!preg_match("/{$this->escapableControlCharactersPattern}/", $escapedString)) { + return $escapedString; + } + + return preg_replace_callback("/({$this->escapableControlCharactersPattern})/", function($matches) { + return $this->controlCharactersEscapingReverseMap[$matches[0]]; + }, $escapedString); + } + + /** + * Escapes the escape character: "_x0000_" -> "_x005F_x0000_" + * + * @param string $string String to escape + * @return string The escaped string + */ + protected function escapeEscapeCharacter($string) + { + return preg_replace('/_(x[\dA-F]{4})_/', '_x005F_$1_', $string); + } + + /** + * Converts OpenXML escaped control characters from the given string to PHP control characters + * + * Excel escapes control characters with _xHHHH_ and also escapes any + * literal strings of that type by encoding the leading underscore. + * So "_x0000_" -> "\0" and "_x005F_x0000_" -> "_x0000_" + * + * NOTE: the logic has been adapted from the XlsxWriter library (BSD License) + * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89 + * + * @param string $string String to unescape + * @return string + */ + protected function unescapeControlCharacters($string) + { + $unescapedString = $string; + + foreach ($this->controlCharactersEscapingMap as $escapedCharValue => $charValue) { + // only unescape characters that don't contain the escaped escape character for now + $unescapedString = preg_replace("/(?unescapeEscapeCharacter($unescapedString); + } + + /** + * Unecapes the escape character: "_x005F_x0000_" => "_x0000_" + * + * @param string $string String to unescape + * @return string The unescaped string + */ + protected function unescapeEscapeCharacter($string) + { + return preg_replace('/_x005F(_x[\dA-F]{4}_)/', '$1', $string); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Exception/EncodingConversionException.php b/lib/vendor/box/spout/src/Spout/Common/Exception/EncodingConversionException.php new file mode 100644 index 0000000000..6dcc0a8d6a --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Exception/EncodingConversionException.php @@ -0,0 +1,13 @@ +globalFunctionsHelper = $globalFunctionsHelper; + + $this->supportedEncodingsWithBom = [ + self::ENCODING_UTF8 => self::BOM_UTF8, + self::ENCODING_UTF16_LE => self::BOM_UTF16_LE, + self::ENCODING_UTF16_BE => self::BOM_UTF16_BE, + self::ENCODING_UTF32_LE => self::BOM_UTF32_LE, + self::ENCODING_UTF32_BE => self::BOM_UTF32_BE, + ]; + } + + /** + * Returns the number of bytes to use as offset in order to skip the BOM. + * + * @param resource $filePointer Pointer to the file to check + * @param string $encoding Encoding of the file to check + * @return int Bytes offset to apply to skip the BOM (0 means no BOM) + */ + public function getBytesOffsetToSkipBOM($filePointer, $encoding) + { + $byteOffsetToSkipBom = 0; + + if ($this->hasBOM($filePointer, $encoding)) { + $bomUsed = $this->supportedEncodingsWithBom[$encoding]; + + // we skip the N first bytes + $byteOffsetToSkipBom = strlen($bomUsed); + } + + return $byteOffsetToSkipBom; + } + + /** + * Returns whether the file identified by the given pointer has a BOM. + * + * @param resource $filePointer Pointer to the file to check + * @param string $encoding Encoding of the file to check + * @return bool TRUE if the file has a BOM, FALSE otherwise + */ + protected function hasBOM($filePointer, $encoding) + { + $hasBOM = false; + + $this->globalFunctionsHelper->rewind($filePointer); + + if (array_key_exists($encoding, $this->supportedEncodingsWithBom)) { + $potentialBom = $this->supportedEncodingsWithBom[$encoding]; + $numBytesInBom = strlen($potentialBom); + + $hasBOM = ($this->globalFunctionsHelper->fgets($filePointer, $numBytesInBom + 1) === $potentialBom); + } + + return $hasBOM; + } + + /** + * Attempts to convert a non UTF-8 string into UTF-8. + * + * @param string $string Non UTF-8 string to be converted + * @param string $sourceEncoding The encoding used to encode the source string + * @return string The converted, UTF-8 string + * @throws \Box\Spout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed + */ + public function attemptConversionToUTF8($string, $sourceEncoding) + { + return $this->attemptConversion($string, $sourceEncoding, self::ENCODING_UTF8); + } + + /** + * Attempts to convert a UTF-8 string into the given encoding. + * + * @param string $string UTF-8 string to be converted + * @param string $targetEncoding The encoding the string should be re-encoded into + * @return string The converted string, encoded with the given encoding + * @throws \Box\Spout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed + */ + public function attemptConversionFromUTF8($string, $targetEncoding) + { + return $this->attemptConversion($string, self::ENCODING_UTF8, $targetEncoding); + } + + /** + * Attempts to convert the given string to the given encoding. + * Depending on what is installed on the server, we will try to iconv or mbstring. + * + * @param string $string string to be converted + * @param string $sourceEncoding The encoding used to encode the source string + * @param string $targetEncoding The encoding the string should be re-encoded into + * @return string The converted string, encoded with the given encoding + * @throws \Box\Spout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed + */ + protected function attemptConversion($string, $sourceEncoding, $targetEncoding) + { + // if source and target encodings are the same, it's a no-op + if ($sourceEncoding === $targetEncoding) { + return $string; + } + + $convertedString = null; + + if ($this->canUseIconv()) { + $convertedString = $this->globalFunctionsHelper->iconv($string, $sourceEncoding, $targetEncoding); + } else if ($this->canUseMbString()) { + $convertedString = $this->globalFunctionsHelper->mb_convert_encoding($string, $sourceEncoding, $targetEncoding); + } else { + throw new EncodingConversionException("The conversion from $sourceEncoding to $targetEncoding is not supported. Please install \"iconv\" or \"PHP Intl\"."); + } + + if ($convertedString === false) { + throw new EncodingConversionException("The conversion from $sourceEncoding to $targetEncoding failed."); + } + + return $convertedString; + } + + /** + * Returns whether "iconv" can be used. + * + * @return bool TRUE if "iconv" is available and can be used, FALSE otherwise + */ + protected function canUseIconv() + { + return $this->globalFunctionsHelper->function_exists('iconv'); + } + + /** + * Returns whether "mb_string" functions can be used. + * These functions come with the PHP Intl package. + * + * @return bool TRUE if "mb_string" functions are available and can be used, FALSE otherwise + */ + protected function canUseMbString() + { + return $this->globalFunctionsHelper->function_exists('mb_convert_encoding'); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Helper/FileSystemHelper.php b/lib/vendor/box/spout/src/Spout/Common/Helper/FileSystemHelper.php new file mode 100644 index 0000000000..3145be73b5 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Helper/FileSystemHelper.php @@ -0,0 +1,133 @@ +baseFolderRealPath = realpath($baseFolderPath); + } + + /** + * Creates an empty folder with the given name under the given parent folder. + * + * @param string $parentFolderPath The parent folder path under which the folder is going to be created + * @param string $folderName The name of the folder to create + * @return string Path of the created folder + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or if the folder path is not inside of the base folder + */ + public function createFolder($parentFolderPath, $folderName) + { + $this->throwIfOperationNotInBaseFolder($parentFolderPath); + + $folderPath = $parentFolderPath . '/' . $folderName; + + $wasCreationSuccessful = mkdir($folderPath, 0777, true); + if (!$wasCreationSuccessful) { + throw new IOException("Unable to create folder: $folderPath"); + } + + return $folderPath; + } + + /** + * Creates a file with the given name and content in the given folder. + * The parent folder must exist. + * + * @param string $parentFolderPath The parent folder path where the file is going to be created + * @param string $fileName The name of the file to create + * @param string $fileContents The contents of the file to create + * @return string Path of the created file + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file or if the file path is not inside of the base folder + */ + public function createFileWithContents($parentFolderPath, $fileName, $fileContents) + { + $this->throwIfOperationNotInBaseFolder($parentFolderPath); + + $filePath = $parentFolderPath . '/' . $fileName; + + $wasCreationSuccessful = file_put_contents($filePath, $fileContents); + if ($wasCreationSuccessful === false) { + throw new IOException("Unable to create file: $filePath"); + } + + return $filePath; + } + + /** + * Delete the file at the given path + * + * @param string $filePath Path of the file to delete + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the file path is not inside of the base folder + */ + public function deleteFile($filePath) + { + $this->throwIfOperationNotInBaseFolder($filePath); + + if (file_exists($filePath) && is_file($filePath)) { + unlink($filePath); + } + } + + /** + * Delete the folder at the given path as well as all its contents + * + * @param string $folderPath Path of the folder to delete + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the folder path is not inside of the base folder + */ + public function deleteFolderRecursively($folderPath) + { + $this->throwIfOperationNotInBaseFolder($folderPath); + + $itemIterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($itemIterator as $item) { + if ($item->isDir()) { + rmdir($item->getPathname()); + } else { + unlink($item->getPathname()); + } + } + + rmdir($folderPath); + } + + /** + * All I/O operations must occur inside the base folder, for security reasons. + * This function will throw an exception if the folder where the I/O operation + * should occur is not inside the base folder. + * + * @param string $operationFolderPath The path of the folder where the I/O operation should occur + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the folder where the I/O operation should occur is not inside the base folder + */ + protected function throwIfOperationNotInBaseFolder($operationFolderPath) + { + $operationFolderRealPath = realpath($operationFolderPath); + $isInBaseFolder = (strpos($operationFolderRealPath, $this->baseFolderRealPath) === 0); + if (!$isInBaseFolder) { + throw new IOException("Cannot perform I/O operation outside of the base folder: {$this->baseFolderRealPath}"); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Helper/GlobalFunctionsHelper.php b/lib/vendor/box/spout/src/Spout/Common/Helper/GlobalFunctionsHelper.php new file mode 100644 index 0000000000..c5d6e31952 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Helper/GlobalFunctionsHelper.php @@ -0,0 +1,318 @@ +convertToUseRealPath($filePath); + return file_get_contents($realFilePath); + } + + /** + * Updates the given file path to use a real path. + * This is to avoid issues on some Windows setup. + * + * @param string $filePath File path + * @return string The file path using a real path + */ + protected function convertToUseRealPath($filePath) + { + $realFilePath = $filePath; + + if ($this->isZipStream($filePath)) { + if (preg_match('/zip:\/\/(.*)#(.*)/', $filePath, $matches)) { + $documentPath = $matches[1]; + $documentInsideZipPath = $matches[2]; + $realFilePath = 'zip://' . realpath($documentPath) . '#' . $documentInsideZipPath; + } + } else { + $realFilePath = realpath($filePath); + } + + return $realFilePath; + } + + /** + * Returns whether the given path is a zip stream. + * + * @param string $path Path pointing to a document + * @return bool TRUE if path is a zip stream, FALSE otherwise + */ + protected function isZipStream($path) + { + return (strpos($path, 'zip://') === 0); + } + + /** + * Wrapper around global function feof() + * @see feof() + * + * @param resource + * @return bool + */ + public function feof($handle) + { + return feof($handle); + } + + /** + * Wrapper around global function is_readable() + * @see is_readable() + * + * @param string $fileName + * @return bool + */ + public function is_readable($fileName) + { + return is_readable($fileName); + } + + /** + * Wrapper around global function basename() + * @see basename() + * + * @param string $path + * @param string|void $suffix + * @return string + */ + public function basename($path, $suffix = null) + { + return basename($path, $suffix); + } + + /** + * Wrapper around global function header() + * @see header() + * + * @param string $string + * @return void + */ + public function header($string) + { + header($string); + } + + /** + * Wrapper around global function ob_end_clean() + * @see ob_end_clean() + * + * @return void + */ + public function ob_end_clean() + { + if (ob_get_length() > 0) { + ob_end_clean(); + } + } + + /** + * Wrapper around global function iconv() + * @see iconv() + * + * @param string $string The string to be converted + * @param string $sourceEncoding The encoding of the source string + * @param string $targetEncoding The encoding the source string should be converted to + * @return string|bool the converted string or FALSE on failure. + */ + public function iconv($string, $sourceEncoding, $targetEncoding) + { + return iconv($sourceEncoding, $targetEncoding, $string); + } + + /** + * Wrapper around global function mb_convert_encoding() + * @see mb_convert_encoding() + * + * @param string $string The string to be converted + * @param string $sourceEncoding The encoding of the source string + * @param string $targetEncoding The encoding the source string should be converted to + * @return string|bool the converted string or FALSE on failure. + */ + public function mb_convert_encoding($string, $sourceEncoding, $targetEncoding) + { + return mb_convert_encoding($string, $targetEncoding, $sourceEncoding); + } + + /** + * Wrapper around global function stream_get_wrappers() + * @see stream_get_wrappers() + * + * @return array + */ + public function stream_get_wrappers() + { + return stream_get_wrappers(); + } + + /** + * Wrapper around global function function_exists() + * @see function_exists() + * + * @param string $functionName + * @return bool + */ + public function function_exists($functionName) + { + return function_exists($functionName); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Helper/StringHelper.php b/lib/vendor/box/spout/src/Spout/Common/Helper/StringHelper.php new file mode 100644 index 0000000000..273104e90c --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Helper/StringHelper.php @@ -0,0 +1,71 @@ +hasMbstringSupport = extension_loaded('mbstring'); + } + + /** + * Returns the length of the given string. + * It uses the multi-bytes function is available. + * @see strlen + * @see mb_strlen + * + * @param string $string + * @return int + */ + public function getStringLength($string) + { + return $this->hasMbstringSupport ? mb_strlen($string) : strlen($string); + } + + /** + * Returns the position of the first occurrence of the given character/substring within the given string. + * It uses the multi-bytes function is available. + * @see strpos + * @see mb_strpos + * + * @param string $char Needle + * @param string $string Haystack + * @return int Char/substring's first occurrence position within the string if found (starts at 0) or -1 if not found + */ + public function getCharFirstOccurrencePosition($char, $string) + { + $position = $this->hasMbstringSupport ? mb_strpos($string, $char) : strpos($string, $char); + return ($position !== false) ? $position : -1; + } + + /** + * Returns the position of the last occurrence of the given character/substring within the given string. + * It uses the multi-bytes function is available. + * @see strrpos + * @see mb_strrpos + * + * @param string $char Needle + * @param string $string Haystack + * @return int Char/substring's last occurrence position within the string if found (starts at 0) or -1 if not found + */ + public function getCharLastOccurrencePosition($char, $string) + { + $position = $this->hasMbstringSupport ? mb_strrpos($string, $char) : strrpos($string, $char); + return ($position !== false) ? $position : -1; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Singleton.php b/lib/vendor/box/spout/src/Spout/Common/Singleton.php new file mode 100644 index 0000000000..015ede8e2f --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Singleton.php @@ -0,0 +1,41 @@ +init(); + } + + /** + * Initializes the singleton + * @return void + */ + protected function init() {} + + final private function __wakeup() {} + final private function __clone() {} +} diff --git a/lib/vendor/box/spout/src/Spout/Common/Type.php b/lib/vendor/box/spout/src/Spout/Common/Type.php new file mode 100644 index 0000000000..5e9b75e614 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Common/Type.php @@ -0,0 +1,16 @@ +globalFunctionsHelper = $globalFunctionsHelper; + return $this; + } + + /** + * Sets whether date/time values should be returned as PHP objects or be formatted as strings. + * + * @api + * @param bool $shouldFormatDates + * @return AbstractReader + */ + public function setShouldFormatDates($shouldFormatDates) + { + $this->getOptions()->setShouldFormatDates($shouldFormatDates); + return $this; + } + + /** + * Sets whether empty rows should be returned or skipped. + * + * @api + * @param bool $shouldPreserveEmptyRows + * @return AbstractReader + */ + public function setShouldPreserveEmptyRows($shouldPreserveEmptyRows) + { + $this->getOptions()->setShouldPreserveEmptyRows($shouldPreserveEmptyRows); + return $this; + } + + /** + * Prepares the reader to read the given file. It also makes sure + * that the file exists and is readable. + * + * @api + * @param string $filePath Path of the file to be read + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the file at the given path does not exist, is not readable or is corrupted + */ + public function open($filePath) + { + if ($this->isStreamWrapper($filePath) && (!$this->doesSupportStreamWrapper() || !$this->isSupportedStreamWrapper($filePath))) { + throw new IOException("Could not open $filePath for reading! Stream wrapper used is not supported for this type of file."); + } + + if (!$this->isPhpStream($filePath)) { + // we skip the checks if the provided file path points to a PHP stream + if (!$this->globalFunctionsHelper->file_exists($filePath)) { + throw new IOException("Could not open $filePath for reading! File does not exist."); + } else if (!$this->globalFunctionsHelper->is_readable($filePath)) { + throw new IOException("Could not open $filePath for reading! File is not readable."); + } + } + + try { + $fileRealPath = $this->getFileRealPath($filePath); + $this->openReader($fileRealPath); + $this->isStreamOpened = true; + } catch (\Exception $exception) { + throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})"); + } + } + + /** + * Returns the real path of the given path. + * If the given path is a valid stream wrapper, returns the path unchanged. + * + * @param string $filePath + * @return string + */ + protected function getFileRealPath($filePath) + { + if ($this->isSupportedStreamWrapper($filePath)) { + return $filePath; + } + + // Need to use realpath to fix "Can't open file" on some Windows setup + return realpath($filePath); + } + + /** + * Returns the scheme of the custom stream wrapper, if the path indicates a stream wrapper is used. + * For example, php://temp => php, s3://path/to/file => s3... + * + * @param string $filePath Path of the file to be read + * @return string|null The stream wrapper scheme or NULL if not a stream wrapper + */ + protected function getStreamWrapperScheme($filePath) + { + $streamScheme = null; + if (preg_match('/^(\w+):\/\//', $filePath, $matches)) { + $streamScheme = $matches[1]; + } + return $streamScheme; + } + + /** + * Checks if the given path is an unsupported stream wrapper + * (like local path, php://temp, mystream://foo/bar...). + * + * @param string $filePath Path of the file to be read + * @return bool Whether the given path is an unsupported stream wrapper + */ + protected function isStreamWrapper($filePath) + { + return ($this->getStreamWrapperScheme($filePath) !== null); + } + + /** + * Checks if the given path is an supported stream wrapper + * (like php://temp, mystream://foo/bar...). + * If the given path is a local path, returns true. + * + * @param string $filePath Path of the file to be read + * @return bool Whether the given path is an supported stream wrapper + */ + protected function isSupportedStreamWrapper($filePath) + { + $streamScheme = $this->getStreamWrapperScheme($filePath); + return ($streamScheme !== null) ? + in_array($streamScheme, $this->globalFunctionsHelper->stream_get_wrappers()) : + true; + } + + /** + * Checks if a path is a PHP stream (like php://output, php://memory, ...) + * + * @param string $filePath Path of the file to be read + * @return bool Whether the given path maps to a PHP stream + */ + protected function isPhpStream($filePath) + { + $streamScheme = $this->getStreamWrapperScheme($filePath); + return ($streamScheme === 'php'); + } + + /** + * Returns an iterator to iterate over sheets. + * + * @api + * @return \Iterator To iterate over sheets + * @throws \Box\Spout\Reader\Exception\ReaderNotOpenedException If called before opening the reader + */ + public function getSheetIterator() + { + if (!$this->isStreamOpened) { + throw new ReaderNotOpenedException('Reader should be opened first.'); + } + + return $this->getConcreteSheetIterator(); + } + + /** + * Closes the reader, preventing any additional reading + * + * @api + * @return void + */ + public function close() + { + if ($this->isStreamOpened) { + $this->closeReader(); + + $sheetIterator = $this->getConcreteSheetIterator(); + if ($sheetIterator) { + $sheetIterator->end(); + } + + $this->isStreamOpened = false; + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/CSV/Reader.php b/lib/vendor/box/spout/src/Spout/Reader/CSV/Reader.php new file mode 100644 index 0000000000..648a12d36a --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/CSV/Reader.php @@ -0,0 +1,149 @@ +options)) { + $this->options = new ReaderOptions(); + } + return $this->options; + } + + /** + * Sets the field delimiter for the CSV. + * Needs to be called before opening the reader. + * + * @param string $fieldDelimiter Character that delimits fields + * @return Reader + */ + public function setFieldDelimiter($fieldDelimiter) + { + $this->getOptions()->setFieldDelimiter($fieldDelimiter); + return $this; + } + + /** + * Sets the field enclosure for the CSV. + * Needs to be called before opening the reader. + * + * @param string $fieldEnclosure Character that enclose fields + * @return Reader + */ + public function setFieldEnclosure($fieldEnclosure) + { + $this->getOptions()->setFieldEnclosure($fieldEnclosure); + return $this; + } + + /** + * Sets the encoding of the CSV file to be read. + * Needs to be called before opening the reader. + * + * @param string $encoding Encoding of the CSV file to be read + * @return Reader + */ + public function setEncoding($encoding) + { + $this->getOptions()->setEncoding($encoding); + return $this; + } + + /** + * Sets the EOL for the CSV. + * Needs to be called before opening the reader. + * + * @param string $endOfLineCharacter used to properly get lines from the CSV file. + * @return Reader + */ + public function setEndOfLineCharacter($endOfLineCharacter) + { + $this->getOptions()->setEndOfLineCharacter($endOfLineCharacter); + return $this; + } + + /** + * Returns whether stream wrappers are supported + * + * @return bool + */ + protected function doesSupportStreamWrapper() + { + return true; + } + + /** + * Opens the file at the given path to make it ready to be read. + * If setEncoding() was not called, it assumes that the file is encoded in UTF-8. + * + * @param string $filePath Path of the CSV file to be read + * @return void + * @throws \Box\Spout\Common\Exception\IOException + */ + protected function openReader($filePath) + { + $this->originalAutoDetectLineEndings = ini_get('auto_detect_line_endings'); + ini_set('auto_detect_line_endings', '1'); + + $this->filePointer = $this->globalFunctionsHelper->fopen($filePath, 'r'); + if (!$this->filePointer) { + throw new IOException("Could not open file $filePath for reading."); + } + + $this->sheetIterator = new SheetIterator( + $this->filePointer, + $this->getOptions(), + $this->globalFunctionsHelper + ); + } + + /** + * Returns an iterator to iterate over sheets. + * + * @return SheetIterator To iterate over sheets + */ + protected function getConcreteSheetIterator() + { + return $this->sheetIterator; + } + + + /** + * Closes the reader. To be used after reading the file. + * + * @return void + */ + protected function closeReader() + { + if ($this->filePointer) { + $this->globalFunctionsHelper->fclose($this->filePointer); + } + + ini_set('auto_detect_line_endings', $this->originalAutoDetectLineEndings); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/CSV/ReaderOptions.php b/lib/vendor/box/spout/src/Spout/Reader/CSV/ReaderOptions.php new file mode 100644 index 0000000000..9a1adb89d9 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/CSV/ReaderOptions.php @@ -0,0 +1,110 @@ +fieldDelimiter; + } + + /** + * Sets the field delimiter for the CSV. + * Needs to be called before opening the reader. + * + * @param string $fieldDelimiter Character that delimits fields + * @return ReaderOptions + */ + public function setFieldDelimiter($fieldDelimiter) + { + $this->fieldDelimiter = $fieldDelimiter; + return $this; + } + + /** + * @return string + */ + public function getFieldEnclosure() + { + return $this->fieldEnclosure; + } + + /** + * Sets the field enclosure for the CSV. + * Needs to be called before opening the reader. + * + * @param string $fieldEnclosure Character that enclose fields + * @return ReaderOptions + */ + public function setFieldEnclosure($fieldEnclosure) + { + $this->fieldEnclosure = $fieldEnclosure; + return $this; + } + + /** + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Sets the encoding of the CSV file to be read. + * Needs to be called before opening the reader. + * + * @param string $encoding Encoding of the CSV file to be read + * @return ReaderOptions + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + return $this; + } + + /** + * @return string EOL for the CSV + */ + public function getEndOfLineCharacter() + { + return $this->endOfLineCharacter; + } + + /** + * Sets the EOL for the CSV. + * Needs to be called before opening the reader. + * + * @param string $endOfLineCharacter used to properly get lines from the CSV file. + * @return ReaderOptions + */ + public function setEndOfLineCharacter($endOfLineCharacter) + { + $this->endOfLineCharacter = $endOfLineCharacter; + return $this; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/CSV/RowIterator.php b/lib/vendor/box/spout/src/Spout/Reader/CSV/RowIterator.php new file mode 100644 index 0000000000..a2a6672c77 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/CSV/RowIterator.php @@ -0,0 +1,260 @@ +filePointer = $filePointer; + $this->fieldDelimiter = $options->getFieldDelimiter(); + $this->fieldEnclosure = $options->getFieldEnclosure(); + $this->encoding = $options->getEncoding(); + $this->inputEOLDelimiter = $options->getEndOfLineCharacter(); + $this->shouldPreserveEmptyRows = $options->shouldPreserveEmptyRows(); + $this->globalFunctionsHelper = $globalFunctionsHelper; + + $this->encodingHelper = new EncodingHelper($globalFunctionsHelper); + } + + /** + * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + */ + public function rewind() + { + $this->rewindAndSkipBom(); + + $this->numReadRows = 0; + $this->rowDataBuffer = null; + + $this->next(); + } + + /** + * This rewinds and skips the BOM if inserted at the beginning of the file + * by moving the file pointer after it, so that it is not read. + * + * @return void + */ + protected function rewindAndSkipBom() + { + $byteOffsetToSkipBom = $this->encodingHelper->getBytesOffsetToSkipBOM($this->filePointer, $this->encoding); + + // sets the cursor after the BOM (0 means no BOM, so rewind it) + $this->globalFunctionsHelper->fseek($this->filePointer, $byteOffsetToSkipBom); + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return ($this->filePointer && !$this->hasReachedEndOfFile); + } + + /** + * Move forward to next element. Reads data for the next unprocessed row. + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + * @throws \Box\Spout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8 + */ + public function next() + { + $this->hasReachedEndOfFile = $this->globalFunctionsHelper->feof($this->filePointer); + + if (!$this->hasReachedEndOfFile) { + $this->readDataForNextRow(); + } + } + + /** + * @return void + * @throws \Box\Spout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8 + */ + protected function readDataForNextRow() + { + do { + $rowData = $this->getNextUTF8EncodedRow(); + } while ($this->shouldReadNextRow($rowData)); + + if ($rowData !== false) { + // str_replace will replace NULL values by empty strings + $this->rowDataBuffer = str_replace(null, null, $rowData); + $this->numReadRows++; + } else { + // If we reach this point, it means end of file was reached. + // This happens when the last lines are empty lines. + $this->hasReachedEndOfFile = true; + } + } + + /** + * @param array|bool $currentRowData + * @return bool Whether the data for the current row can be returned or if we need to keep reading + */ + protected function shouldReadNextRow($currentRowData) + { + $hasSuccessfullyFetchedRowData = ($currentRowData !== false); + $hasNowReachedEndOfFile = $this->globalFunctionsHelper->feof($this->filePointer); + $isEmptyLine = $this->isEmptyLine($currentRowData); + + return ( + (!$hasSuccessfullyFetchedRowData && !$hasNowReachedEndOfFile) || + (!$this->shouldPreserveEmptyRows && $isEmptyLine) + ); + } + + /** + * Returns the next row, converted if necessary to UTF-8. + * As fgetcsv() does not manage correctly encoding for non UTF-8 data, + * we remove manually whitespace with ltrim or rtrim (depending on the order of the bytes) + * + * @return array|false The row for the current file pointer, encoded in UTF-8 or FALSE if nothing to read + * @throws \Box\Spout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8 + */ + protected function getNextUTF8EncodedRow() + { + $encodedRowData = $this->globalFunctionsHelper->fgetcsv($this->filePointer, self::MAX_READ_BYTES_PER_LINE, $this->fieldDelimiter, $this->fieldEnclosure); + if ($encodedRowData === false) { + return false; + } + + foreach ($encodedRowData as $cellIndex => $cellValue) { + switch($this->encoding) { + case EncodingHelper::ENCODING_UTF16_LE: + case EncodingHelper::ENCODING_UTF32_LE: + // remove whitespace from the beginning of a string as fgetcsv() add extra whitespace when it try to explode non UTF-8 data + $cellValue = ltrim($cellValue); + break; + + case EncodingHelper::ENCODING_UTF16_BE: + case EncodingHelper::ENCODING_UTF32_BE: + // remove whitespace from the end of a string as fgetcsv() add extra whitespace when it try to explode non UTF-8 data + $cellValue = rtrim($cellValue); + break; + } + + $encodedRowData[$cellIndex] = $this->encodingHelper->attemptConversionToUTF8($cellValue, $this->encoding); + } + + return $encodedRowData; + } + + /** + * Returns the end of line delimiter, encoded using the same encoding as the CSV. + * The return value is cached. + * + * @return string + */ + protected function getEncodedEOLDelimiter() + { + if (!isset($this->encodedEOLDelimiter)) { + $this->encodedEOLDelimiter = $this->encodingHelper->attemptConversionFromUTF8($this->inputEOLDelimiter, $this->encoding); + } + + return $this->encodedEOLDelimiter; + } + + /** + * @param array|bool $lineData Array containing the cells value for the line + * @return bool Whether the given line is empty + */ + protected function isEmptyLine($lineData) + { + return (is_array($lineData) && count($lineData) === 1 && $lineData[0] === null); + } + + /** + * Return the current element from the buffer + * @link http://php.net/manual/en/iterator.current.php + * + * @return array|null + */ + public function current() + { + return $this->rowDataBuffer; + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + return $this->numReadRows; + } + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + // do nothing + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/CSV/Sheet.php b/lib/vendor/box/spout/src/Spout/Reader/CSV/Sheet.php new file mode 100644 index 0000000000..9a688db0da --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/CSV/Sheet.php @@ -0,0 +1,62 @@ +rowIterator = new RowIterator($filePointer, $options, $globalFunctionsHelper); + } + + /** + * @api + * @return \Box\Spout\Reader\CSV\RowIterator + */ + public function getRowIterator() + { + return $this->rowIterator; + } + + /** + * @api + * @return int Index of the sheet + */ + public function getIndex() + { + return 0; + } + + /** + * @api + * @return string Name of the sheet - empty string since CSV does not support that + */ + public function getName() + { + return ''; + } + + /** + * @api + * @return bool Always TRUE as there is only one sheet + */ + public function isActive() + { + return true; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/CSV/SheetIterator.php b/lib/vendor/box/spout/src/Spout/Reader/CSV/SheetIterator.php new file mode 100644 index 0000000000..58a9480c4b --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/CSV/SheetIterator.php @@ -0,0 +1,95 @@ +sheet = new Sheet($filePointer, $options, $globalFunctionsHelper); + } + + /** + * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + */ + public function rewind() + { + $this->hasReadUniqueSheet = false; + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return (!$this->hasReadUniqueSheet); + } + + /** + * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + */ + public function next() + { + $this->hasReadUniqueSheet = true; + } + + /** + * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * + * @return \Box\Spout\Reader\CSV\Sheet + */ + public function current() + { + return $this->sheet; + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + return 1; + } + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + // do nothing + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/Common/ReaderOptions.php b/lib/vendor/box/spout/src/Spout/Reader/Common/ReaderOptions.php new file mode 100644 index 0000000000..4ab7a07f48 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/Common/ReaderOptions.php @@ -0,0 +1,58 @@ +shouldFormatDates; + } + + /** + * Sets whether date/time values should be returned as PHP objects or be formatted as strings. + * + * @param bool $shouldFormatDates + * @return ReaderOptions + */ + public function setShouldFormatDates($shouldFormatDates) + { + $this->shouldFormatDates = $shouldFormatDates; + return $this; + } + + /** + * @return bool Whether empty rows should be returned or skipped. + */ + public function shouldPreserveEmptyRows() + { + return $this->shouldPreserveEmptyRows; + } + + /** + * Sets whether empty rows should be returned or skipped. + * + * @param bool $shouldPreserveEmptyRows + * @return ReaderOptions + */ + public function setShouldPreserveEmptyRows($shouldPreserveEmptyRows) + { + $this->shouldPreserveEmptyRows = $shouldPreserveEmptyRows; + return $this; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/Common/XMLProcessor.php b/lib/vendor/box/spout/src/Spout/Reader/Common/XMLProcessor.php new file mode 100644 index 0000000000..d8a1da8d27 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/Common/XMLProcessor.php @@ -0,0 +1,152 @@ +xmlReader = $xmlReader; + } + + /** + * @param string $nodeName A callback may be triggered when a node with this name is read + * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END] + * @param callable $callback Callback to execute when the read node has the given name and type + * @return XMLProcessor + */ + public function registerCallback($nodeName, $nodeType, $callback) + { + $callbackKey = $this->getCallbackKey($nodeName, $nodeType); + $this->callbacks[$callbackKey] = $this->getInvokableCallbackData($callback); + + return $this; + } + + /** + * @param string $nodeName Name of the node + * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END] + * @return string Key used to store the associated callback + */ + private function getCallbackKey($nodeName, $nodeType) + { + return "$nodeName$nodeType"; + } + + /** + * Because the callback can be a "protected" function, we don't want to use call_user_func() directly + * but instead invoke the callback using Reflection. This allows the invocation of "protected" functions. + * Since some functions can be called a lot, we pre-process the callback to only return the elements that + * will be needed to invoke the callback later. + * + * @param callable $callback Array reference to a callback: [OBJECT, METHOD_NAME] + * @return array Associative array containing the elements needed to invoke the callback using Reflection + */ + private function getInvokableCallbackData($callback) + { + $callbackObject = $callback[0]; + $callbackMethodName = $callback[1]; + $reflectionMethod = new \ReflectionMethod(get_class($callbackObject), $callbackMethodName); + $reflectionMethod->setAccessible(true); + + return [ + self::CALLBACK_REFLECTION_METHOD => $reflectionMethod, + self::CALLBACK_REFLECTION_OBJECT => $callbackObject, + ]; + } + + /** + * Resumes the reading of the XML file where it was left off. + * Stops whenever a callback indicates that reading should stop or at the end of the file. + * + * @return void + * @throws \Box\Spout\Reader\Exception\XMLProcessingException + */ + public function readUntilStopped() + { + while ($this->xmlReader->read()) { + $nodeType = $this->xmlReader->nodeType; + $nodeNamePossiblyWithPrefix = $this->xmlReader->name; + $nodeNameWithoutPrefix = $this->xmlReader->localName; + + $callbackData = $this->getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType); + + if ($callbackData !== null) { + $callbackResponse = $this->invokeCallback($callbackData, [$this->xmlReader]); + + if ($callbackResponse === self::PROCESSING_STOP) { + // stop reading + break; + } + } + } + } + + /** + * @param string $nodeNamePossiblyWithPrefix Name of the node, possibly prefixed + * @param string $nodeNameWithoutPrefix Name of the same node, un-prefixed + * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END] + * @return array|null Callback data to be used for execution when a node of the given name/type is read or NULL if none found + */ + private function getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType) + { + // With prefixed nodes, we should match if (by order of preference): + // 1. the callback was registered with the prefixed node name (e.g. "x:worksheet") + // 2. the callback was registered with the un-prefixed node name (e.g. "worksheet") + $callbackKeyForPossiblyPrefixedName = $this->getCallbackKey($nodeNamePossiblyWithPrefix, $nodeType); + $callbackKeyForUnPrefixedName = $this->getCallbackKey($nodeNameWithoutPrefix, $nodeType); + $hasPrefix = ($nodeNamePossiblyWithPrefix !== $nodeNameWithoutPrefix); + + $callbackKeyToUse = $callbackKeyForUnPrefixedName; + if ($hasPrefix && isset($this->callbacks[$callbackKeyForPossiblyPrefixedName])) { + $callbackKeyToUse = $callbackKeyForPossiblyPrefixedName; + } + + // Using isset here because it is way faster than array_key_exists... + return isset($this->callbacks[$callbackKeyToUse]) ? $this->callbacks[$callbackKeyToUse] : null; + } + + /** + * @param array $callbackData Associative array containing data to invoke the callback using Reflection + * @param array $args Arguments to pass to the callback + * @return int Callback response + */ + private function invokeCallback($callbackData, $args) + { + $reflectionMethod = $callbackData[self::CALLBACK_REFLECTION_METHOD]; + $callbackObject = $callbackData[self::CALLBACK_REFLECTION_OBJECT]; + + return $reflectionMethod->invokeArgs($callbackObject, $args); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/Exception/IteratorNotRewindableException.php b/lib/vendor/box/spout/src/Spout/Reader/Exception/IteratorNotRewindableException.php new file mode 100644 index 0000000000..a030c121e8 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/Exception/IteratorNotRewindableException.php @@ -0,0 +1,13 @@ +shouldFormatDates = $shouldFormatDates; + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->escaper = \Box\Spout\Common\Escaper\ODS::getInstance(); + } + + /** + * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node. + * @see http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#refTable13 + * + * @param \DOMNode $node + * @return string|int|float|bool|\DateTime|\DateInterval|null The value associated with the cell, empty string if cell's type is void/undefined, null on error + */ + public function extractAndFormatNodeValue($node) + { + $cellType = $node->getAttribute(self::XML_ATTRIBUTE_TYPE); + + switch ($cellType) { + case self::CELL_TYPE_STRING: + return $this->formatStringCellValue($node); + case self::CELL_TYPE_FLOAT: + return $this->formatFloatCellValue($node); + case self::CELL_TYPE_BOOLEAN: + return $this->formatBooleanCellValue($node); + case self::CELL_TYPE_DATE: + return $this->formatDateCellValue($node); + case self::CELL_TYPE_TIME: + return $this->formatTimeCellValue($node); + case self::CELL_TYPE_CURRENCY: + return $this->formatCurrencyCellValue($node); + case self::CELL_TYPE_PERCENTAGE: + return $this->formatPercentageCellValue($node); + case self::CELL_TYPE_VOID: + default: + return ''; + } + } + + /** + * Returns the cell String value. + * + * @param \DOMNode $node + * @return string The value associated with the cell + */ + protected function formatStringCellValue($node) + { + $pNodeValues = []; + $pNodes = $node->getElementsByTagName(self::XML_NODE_P); + + foreach ($pNodes as $pNode) { + $currentPValue = ''; + + foreach ($pNode->childNodes as $childNode) { + if ($childNode instanceof \DOMText) { + $currentPValue .= $childNode->nodeValue; + } else if ($childNode->nodeName === self::XML_NODE_S) { + $spaceAttribute = $childNode->getAttribute(self::XML_ATTRIBUTE_C); + $numSpaces = (!empty($spaceAttribute)) ? intval($spaceAttribute) : 1; + $currentPValue .= str_repeat(' ', $numSpaces); + } else if ($childNode->nodeName === self::XML_NODE_A || $childNode->nodeName === self::XML_NODE_SPAN) { + $currentPValue .= $childNode->nodeValue; + } + } + + $pNodeValues[] = $currentPValue; + } + + $escapedCellValue = implode("\n", $pNodeValues); + $cellValue = $this->escaper->unescape($escapedCellValue); + return $cellValue; + } + + /** + * Returns the cell Numeric value from the given node. + * + * @param \DOMNode $node + * @return int|float The value associated with the cell + */ + protected function formatFloatCellValue($node) + { + $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_VALUE); + $nodeIntValue = intval($nodeValue); + // The "==" is intentionally not a "===" because only the value matters, not the type + $cellValue = ($nodeIntValue == $nodeValue) ? $nodeIntValue : floatval($nodeValue); + return $cellValue; + } + + /** + * Returns the cell Boolean value from the given node. + * + * @param \DOMNode $node + * @return bool The value associated with the cell + */ + protected function formatBooleanCellValue($node) + { + $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_BOOLEAN_VALUE); + // !! is similar to boolval() + $cellValue = !!$nodeValue; + return $cellValue; + } + + /** + * Returns the cell Date value from the given node. + * + * @param \DOMNode $node + * @return \DateTime|string|null The value associated with the cell or NULL if invalid date value + */ + protected function formatDateCellValue($node) + { + // The XML node looks like this: + // + // 05/19/16 04:39 PM + // + + if ($this->shouldFormatDates) { + // The date is already formatted in the "p" tag + $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0); + return $nodeWithValueAlreadyFormatted->nodeValue; + } else { + // otherwise, get it from the "date-value" attribute + try { + $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_DATE_VALUE); + return new \DateTime($nodeValue); + } catch (\Exception $e) { + return null; + } + } + } + + /** + * Returns the cell Time value from the given node. + * + * @param \DOMNode $node + * @return \DateInterval|string|null The value associated with the cell or NULL if invalid time value + */ + protected function formatTimeCellValue($node) + { + // The XML node looks like this: + // + // 01:24:00 PM + // + + if ($this->shouldFormatDates) { + // The date is already formatted in the "p" tag + $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0); + return $nodeWithValueAlreadyFormatted->nodeValue; + } else { + // otherwise, get it from the "time-value" attribute + try { + $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_TIME_VALUE); + return new \DateInterval($nodeValue); + } catch (\Exception $e) { + return null; + } + } + } + + /** + * Returns the cell Currency value from the given node. + * + * @param \DOMNode $node + * @return string The value associated with the cell (e.g. "100 USD" or "9.99 EUR") + */ + protected function formatCurrencyCellValue($node) + { + $value = $node->getAttribute(self::XML_ATTRIBUTE_VALUE); + $currency = $node->getAttribute(self::XML_ATTRIBUTE_CURRENCY); + + return "$value $currency"; + } + + /** + * Returns the cell Percentage value from the given node. + * + * @param \DOMNode $node + * @return int|float The value associated with the cell + */ + protected function formatPercentageCellValue($node) + { + // percentages are formatted like floats + return $this->formatFloatCellValue($node); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ODS/Helper/SettingsHelper.php b/lib/vendor/box/spout/src/Spout/Reader/ODS/Helper/SettingsHelper.php new file mode 100644 index 0000000000..a5388ef4b6 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ODS/Helper/SettingsHelper.php @@ -0,0 +1,51 @@ +openFileInZip($filePath, self::SETTINGS_XML_FILE_PATH) === false) { + return null; + } + + $activeSheetName = null; + + try { + while ($xmlReader->readUntilNodeFound(self::XML_NODE_CONFIG_ITEM)) { + if ($xmlReader->getAttribute(self::XML_ATTRIBUTE_CONFIG_NAME) === self::XML_ATTRIBUTE_VALUE_ACTIVE_TABLE) { + $activeSheetName = $xmlReader->readString(); + break; + } + } + } catch (XMLProcessingException $exception) { + // do nothing + } + + $xmlReader->close(); + + return $activeSheetName; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ODS/Reader.php b/lib/vendor/box/spout/src/Spout/Reader/ODS/Reader.php new file mode 100644 index 0000000000..dbdc47b8db --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ODS/Reader.php @@ -0,0 +1,85 @@ +options)) { + $this->options = new ReaderOptions(); + } + return $this->options; + } + + /** + * Returns whether stream wrappers are supported + * + * @return bool + */ + protected function doesSupportStreamWrapper() + { + return false; + } + + /** + * Opens the file at the given file path to make it ready to be read. + * + * @param string $filePath Path of the file to be read + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the file at the given path or its content cannot be read + * @throws \Box\Spout\Reader\Exception\NoSheetsFoundException If there are no sheets in the file + */ + protected function openReader($filePath) + { + $this->zip = new \ZipArchive(); + + if ($this->zip->open($filePath) === true) { + $this->sheetIterator = new SheetIterator($filePath, $this->getOptions()); + } else { + throw new IOException("Could not open $filePath for reading."); + } + } + + /** + * Returns an iterator to iterate over sheets. + * + * @return SheetIterator To iterate over sheets + */ + protected function getConcreteSheetIterator() + { + return $this->sheetIterator; + } + + /** + * Closes the reader. To be used after reading the file. + * + * @return void + */ + protected function closeReader() + { + if ($this->zip) { + $this->zip->close(); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ODS/ReaderOptions.php b/lib/vendor/box/spout/src/Spout/Reader/ODS/ReaderOptions.php new file mode 100644 index 0000000000..2d29640f3e --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ODS/ReaderOptions.php @@ -0,0 +1,14 @@ +" element + * @param \Box\Spout\Reader\ODS\ReaderOptions $options Reader's current options + */ + public function __construct($xmlReader, $options) + { + $this->xmlReader = $xmlReader; + $this->shouldPreserveEmptyRows = $options->shouldPreserveEmptyRows(); + $this->cellValueFormatter = new CellValueFormatter($options->shouldFormatDates()); + + // Register all callbacks to process different nodes when reading the XML file + $this->xmlProcessor = new XMLProcessor($this->xmlReader); + $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_START, [$this, 'processRowStartingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_CELL, XMLProcessor::NODE_TYPE_START, [$this, 'processCellStartingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_END, [$this, 'processRowEndingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_TABLE, XMLProcessor::NODE_TYPE_END, [$this, 'processTableEndingNode']); + } + + /** + * Rewind the Iterator to the first element. + * NOTE: It can only be done once, as it is not possible to read an XML file backwards. + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + * @throws \Box\Spout\Reader\Exception\IteratorNotRewindableException If the iterator is rewound more than once + */ + public function rewind() + { + // Because sheet and row data is located in the file, we can't rewind both the + // sheet iterator and the row iterator, as XML file cannot be read backwards. + // Therefore, rewinding the row iterator has been disabled. + if ($this->hasAlreadyBeenRewound) { + throw new IteratorNotRewindableException(); + } + + $this->hasAlreadyBeenRewound = true; + $this->lastRowIndexProcessed = 0; + $this->nextRowIndexToBeProcessed = 1; + $this->rowDataBuffer = null; + $this->hasReachedEndOfFile = false; + + $this->next(); + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return (!$this->hasReachedEndOfFile); + } + + /** + * Move forward to next element. Empty rows will be skipped. + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If a shared string was not found + * @throws \Box\Spout\Common\Exception\IOException If unable to read the sheet data XML + */ + public function next() + { + if ($this->doesNeedDataForNextRowToBeProcessed()) { + $this->readDataForNextRow(); + } + + $this->lastRowIndexProcessed++; + } + + /** + * Returns whether we need data for the next row to be processed. + * We DO need to read data if: + * - we have not read any rows yet + * OR + * - the next row to be processed immediately follows the last read row + * + * @return bool Whether we need data for the next row to be processed. + */ + protected function doesNeedDataForNextRowToBeProcessed() + { + $hasReadAtLeastOneRow = ($this->lastRowIndexProcessed !== 0); + + return ( + !$hasReadAtLeastOneRow || + $this->lastRowIndexProcessed === $this->nextRowIndexToBeProcessed - 1 + ); + } + + /** + * @return void + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If a shared string was not found + * @throws \Box\Spout\Common\Exception\IOException If unable to read the sheet data XML + */ + protected function readDataForNextRow() + { + $this->currentlyProcessedRowData = []; + + try { + $this->xmlProcessor->readUntilStopped(); + } catch (XMLProcessingException $exception) { + throw new IOException("The sheet's data cannot be read. [{$exception->getMessage()}]"); + } + + $this->rowDataBuffer = $this->currentlyProcessedRowData; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int A return code that indicates what action should the processor take next + */ + protected function processRowStartingNode($xmlReader) + { + // Reset data from current row + $this->hasAlreadyReadOneCellInCurrentRow = false; + $this->lastProcessedCellValue = null; + $this->numColumnsRepeated = 1; + $this->numRowsRepeated = $this->getNumRowsRepeatedForCurrentNode($xmlReader); + + return XMLProcessor::PROCESSING_CONTINUE; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int A return code that indicates what action should the processor take next + */ + protected function processCellStartingNode($xmlReader) + { + $currentNumColumnsRepeated = $this->getNumColumnsRepeatedForCurrentNode($xmlReader); + + // NOTE: expand() will automatically decode all XML entities of the child nodes + $node = $xmlReader->expand(); + $currentCellValue = $this->getCellValue($node); + + // process cell N only after having read cell N+1 (see below why) + if ($this->hasAlreadyReadOneCellInCurrentRow) { + for ($i = 0; $i < $this->numColumnsRepeated; $i++) { + $this->currentlyProcessedRowData[] = $this->lastProcessedCellValue; + } + } + + $this->hasAlreadyReadOneCellInCurrentRow = true; + $this->lastProcessedCellValue = $currentCellValue; + $this->numColumnsRepeated = $currentNumColumnsRepeated; + + return XMLProcessor::PROCESSING_CONTINUE; + } + + /** + * @return int A return code that indicates what action should the processor take next + */ + protected function processRowEndingNode() + { + $isEmptyRow = $this->isEmptyRow($this->currentlyProcessedRowData, $this->lastProcessedCellValue); + + // if the fetched row is empty and we don't want to preserve it... + if (!$this->shouldPreserveEmptyRows && $isEmptyRow) { + // ... skip it + return XMLProcessor::PROCESSING_CONTINUE; + } + + // if the row is empty, we don't want to return more than one cell + $actualNumColumnsRepeated = (!$isEmptyRow) ? $this->numColumnsRepeated : 1; + + // Only add the value if the last read cell is not a trailing empty cell repeater in Excel. + // The current count of read columns is determined by counting the values in "$this->currentlyProcessedRowData". + // This is to avoid creating a lot of empty cells, as Excel adds a last empty "" + // with a number-columns-repeated value equals to the number of (supported columns - used columns). + // In Excel, the number of supported columns is 16384, but we don't want to returns rows with + // always 16384 cells. + if ((count($this->currentlyProcessedRowData) + $actualNumColumnsRepeated) !== self::MAX_COLUMNS_EXCEL) { + for ($i = 0; $i < $actualNumColumnsRepeated; $i++) { + $this->currentlyProcessedRowData[] = $this->lastProcessedCellValue; + } + } + + // If we are processing row N and the row is repeated M times, + // then the next row to be processed will be row (N+M). + $this->nextRowIndexToBeProcessed += $this->numRowsRepeated; + + // at this point, we have all the data we need for the row + // so that we can populate the buffer + return XMLProcessor::PROCESSING_STOP; + } + + /** + * @return int A return code that indicates what action should the processor take next + */ + protected function processTableEndingNode() + { + // The closing "" marks the end of the file + $this->hasReachedEndOfFile = true; + + return XMLProcessor::PROCESSING_STOP; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int The value of "table:number-rows-repeated" attribute of the current node, or 1 if attribute missing + */ + protected function getNumRowsRepeatedForCurrentNode($xmlReader) + { + $numRowsRepeated = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_ROWS_REPEATED); + return ($numRowsRepeated !== null) ? intval($numRowsRepeated) : 1; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int The value of "table:number-columns-repeated" attribute of the current node, or 1 if attribute missing + */ + protected function getNumColumnsRepeatedForCurrentNode($xmlReader) + { + $numColumnsRepeated = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_COLUMNS_REPEATED); + return ($numColumnsRepeated !== null) ? intval($numColumnsRepeated) : 1; + } + + /** + * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node. + * + * @param \DOMNode $node + * @return string|int|float|bool|\DateTime|\DateInterval|null The value associated with the cell, empty string if cell's type is void/undefined, null on error + */ + protected function getCellValue($node) + { + return $this->cellValueFormatter->extractAndFormatNodeValue($node); + } + + /** + * After finishing processing each cell, a row is considered empty if it contains + * no cells or if the value of the last read cell is an empty string. + * After finishing processing each cell, the last read cell is not part of the + * row data yet (as we still need to apply the "num-columns-repeated" attribute). + * + * @param array $rowData + * @param string|int|float|bool|\DateTime|\DateInterval|null The value of the last read cell + * @return bool Whether the row is empty + */ + protected function isEmptyRow($rowData, $lastReadCellValue) + { + return ( + count($rowData) === 0 && + (!isset($lastReadCellValue) || trim($lastReadCellValue) === '') + ); + } + + /** + * Return the current element, from the buffer. + * @link http://php.net/manual/en/iterator.current.php + * + * @return array|null + */ + public function current() + { + return $this->rowDataBuffer; + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + return $this->lastRowIndexProcessed; + } + + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + $this->xmlReader->close(); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ODS/Sheet.php b/lib/vendor/box/spout/src/Spout/Reader/ODS/Sheet.php new file mode 100644 index 0000000000..794ad3a3ae --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ODS/Sheet.php @@ -0,0 +1,81 @@ +" element + * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) + * @param string $sheetName Name of the sheet + * @param bool $isSheetActive Whether the sheet was defined as active + * @param \Box\Spout\Reader\ODS\ReaderOptions $options Reader's current options + */ + public function __construct($xmlReader, $sheetIndex, $sheetName, $isSheetActive, $options) + { + $this->rowIterator = new RowIterator($xmlReader, $options); + $this->index = $sheetIndex; + $this->name = $sheetName; + $this->isActive = $isSheetActive; + } + + /** + * @api + * @return \Box\Spout\Reader\ODS\RowIterator + */ + public function getRowIterator() + { + return $this->rowIterator; + } + + /** + * @api + * @return int Index of the sheet, based on order in the workbook (zero-based) + */ + public function getIndex() + { + return $this->index; + } + + /** + * @api + * @return string Name of the sheet + */ + public function getName() + { + return $this->name; + } + + /** + * @api + * @return bool Whether the sheet was defined as active + */ + public function isActive() + { + return $this->isActive; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ODS/SheetIterator.php b/lib/vendor/box/spout/src/Spout/Reader/ODS/SheetIterator.php new file mode 100644 index 0000000000..995c13601a --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ODS/SheetIterator.php @@ -0,0 +1,168 @@ +filePath = $filePath; + $this->options = $options; + $this->xmlReader = new XMLReader(); + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->escaper = \Box\Spout\Common\Escaper\ODS::getInstance(); + + $settingsHelper = new SettingsHelper(); + $this->activeSheetName = $settingsHelper->getActiveSheetName($filePath); + } + + /** + * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to open the XML file containing sheets' data + */ + public function rewind() + { + $this->xmlReader->close(); + + if ($this->xmlReader->openFileInZip($this->filePath, self::CONTENT_XML_FILE_PATH) === false) { + $contentXmlFilePath = $this->filePath . '#' . self::CONTENT_XML_FILE_PATH; + throw new IOException("Could not open \"{$contentXmlFilePath}\"."); + } + + try { + $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE); + } catch (XMLProcessingException $exception) { + throw new IOException("The content.xml file is invalid and cannot be read. [{$exception->getMessage()}]"); + } + + $this->currentSheetIndex = 0; + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return $this->hasFoundSheet; + } + + /** + * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + */ + public function next() + { + $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE); + + if ($this->hasFoundSheet) { + $this->currentSheetIndex++; + } + } + + /** + * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * + * @return \Box\Spout\Reader\ODS\Sheet + */ + public function current() + { + $escapedSheetName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_NAME); + $sheetName = $this->escaper->unescape($escapedSheetName); + $isActiveSheet = $this->isActiveSheet($sheetName, $this->currentSheetIndex, $this->activeSheetName); + + return new Sheet($this->xmlReader, $this->currentSheetIndex, $sheetName, $isActiveSheet, $this->options); + } + + /** + * Returns whether the current sheet was defined as the active one + * + * @param string $sheetName Name of the current sheet + * @param int $sheetIndex Index of the current sheet + * @param string|null Name of the sheet that was defined as active or NULL if none defined + * @return bool Whether the current sheet was defined as the active one + */ + private function isActiveSheet($sheetName, $sheetIndex, $activeSheetName) + { + // The given sheet is active if its name matches the defined active sheet's name + // or if no information about the active sheet was found, it defaults to the first sheet. + return ( + ($activeSheetName === null && $sheetIndex === 0) || + ($activeSheetName === $sheetName) + ); + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + return $this->currentSheetIndex + 1; + } + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + $this->xmlReader->close(); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ReaderFactory.php b/lib/vendor/box/spout/src/Spout/Reader/ReaderFactory.php new file mode 100644 index 0000000000..93a52cb867 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ReaderFactory.php @@ -0,0 +1,48 @@ +setGlobalFunctionsHelper(new GlobalFunctionsHelper()); + + return $reader; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/ReaderInterface.php b/lib/vendor/box/spout/src/Spout/Reader/ReaderInterface.php new file mode 100644 index 0000000000..8ecde30802 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/ReaderInterface.php @@ -0,0 +1,36 @@ +initialUseInternalErrorsValue = libxml_use_internal_errors(true); + } + + /** + * Throws an XMLProcessingException if an error occured. + * It also always resets the "libxml_use_internal_errors" setting back to its initial value. + * + * @return void + * @throws \Box\Spout\Reader\Exception\XMLProcessingException + */ + protected function resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured() + { + if ($this->hasXMLErrorOccured()) { + $this->resetXMLInternalErrorsSetting(); + throw new XMLProcessingException($this->getLastXMLErrorMessage()); + } + + $this->resetXMLInternalErrorsSetting(); + } + + /** + * Returns whether the a XML error has occured since the last time errors were cleared. + * + * @return bool TRUE if an error occured, FALSE otherwise + */ + private function hasXMLErrorOccured() + { + return (libxml_get_last_error() !== false); + } + + /** + * Returns the error message for the last XML error that occured. + * @see libxml_get_last_error + * + * @return String|null Last XML error message or null if no error + */ + private function getLastXMLErrorMessage() + { + $errorMessage = null; + $error = libxml_get_last_error(); + + if ($error !== false) { + $errorMessage = trim($error->message); + } + + return $errorMessage; + } + + /** + * @return void + */ + protected function resetXMLInternalErrorsSetting() + { + libxml_use_internal_errors($this->initialUseInternalErrorsValue); + } + +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/Wrapper/XMLReader.php b/lib/vendor/box/spout/src/Spout/Reader/Wrapper/XMLReader.php new file mode 100644 index 0000000000..08e99fc656 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/Wrapper/XMLReader.php @@ -0,0 +1,175 @@ +getRealPathURIForFileInZip($zipFilePath, $fileInsideZipPath); + + // We need to check first that the file we are trying to read really exist because: + // - PHP emits a warning when trying to open a file that does not exist. + // - HHVM does not check if file exists within zip file (@link https://github.com/facebook/hhvm/issues/5779) + if ($this->fileExistsWithinZip($realPathURI)) { + $wasOpenSuccessful = $this->open($realPathURI, null, LIBXML_NONET); + } + + return $wasOpenSuccessful; + } + + /** + * Returns the real path for the given path components. + * This is useful to avoid issues on some Windows setup. + * + * @param string $zipFilePath Path to the ZIP file + * @param string $fileInsideZipPath Relative or absolute path of the file inside the zip + * @return string The real path URI + */ + public function getRealPathURIForFileInZip($zipFilePath, $fileInsideZipPath) + { + return (self::ZIP_WRAPPER . realpath($zipFilePath) . '#' . $fileInsideZipPath); + } + + /** + * Returns whether the file at the given location exists + * + * @param string $zipStreamURI URI of a zip stream, e.g. "zip://file.zip#path/inside.xml" + * @return bool TRUE if the file exists, FALSE otherwise + */ + protected function fileExistsWithinZip($zipStreamURI) + { + $doesFileExists = false; + + $pattern = '/zip:\/\/([^#]+)#(.*)/'; + if (preg_match($pattern, $zipStreamURI, $matches)) { + $zipFilePath = $matches[1]; + $innerFilePath = $matches[2]; + + $zip = new \ZipArchive(); + if ($zip->open($zipFilePath) === true) { + $doesFileExists = ($zip->locateName($innerFilePath) !== false); + $zip->close(); + } + } + + return $doesFileExists; + } + + /** + * Move to next node in document + * @see \XMLReader::read + * + * @return bool TRUE on success or FALSE on failure + * @throws \Box\Spout\Reader\Exception\XMLProcessingException If an error/warning occurred + */ + public function read() + { + $this->useXMLInternalErrors(); + + $wasReadSuccessful = parent::read(); + + $this->resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured(); + + return $wasReadSuccessful; + } + + /** + * Read until the element with the given name is found, or the end of the file. + * + * @param string $nodeName Name of the node to find + * @return bool TRUE on success or FALSE on failure + * @throws \Box\Spout\Reader\Exception\XMLProcessingException If an error/warning occurred + */ + public function readUntilNodeFound($nodeName) + { + do { + $wasReadSuccessful = $this->read(); + $isNotPositionedOnStartingNode = !$this->isPositionedOnStartingNode($nodeName); + } while ($wasReadSuccessful && $isNotPositionedOnStartingNode); + + return $wasReadSuccessful; + } + + /** + * Move cursor to next node skipping all subtrees + * @see \XMLReader::next + * + * @param string|void $localName The name of the next node to move to + * @return bool TRUE on success or FALSE on failure + * @throws \Box\Spout\Reader\Exception\XMLProcessingException If an error/warning occurred + */ + public function next($localName = null) + { + $this->useXMLInternalErrors(); + + $wasNextSuccessful = parent::next($localName); + + $this->resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured(); + + return $wasNextSuccessful; + } + + /** + * @param string $nodeName + * @return bool Whether the XML Reader is currently positioned on the starting node with given name + */ + public function isPositionedOnStartingNode($nodeName) + { + return $this->isPositionedOnNode($nodeName, XMLReader::ELEMENT); + } + + /** + * @param string $nodeName + * @return bool Whether the XML Reader is currently positioned on the ending node with given name + */ + public function isPositionedOnEndingNode($nodeName) + { + return $this->isPositionedOnNode($nodeName, XMLReader::END_ELEMENT); + } + + /** + * @param string $nodeName + * @param int $nodeType + * @return bool Whether the XML Reader is currently positioned on the node with given name and type + */ + private function isPositionedOnNode($nodeName, $nodeType) + { + // In some cases, the node has a prefix (for instance, "" can also be ""). + // So if the given node name does not have a prefix, we need to look at the unprefixed name ("localName"). + // @see https://github.com/box/spout/issues/233 + $hasPrefix = (strpos($nodeName, ':') !== false); + $currentNodeName = ($hasPrefix) ? $this->name : $this->localName; + + return ($this->nodeType === $nodeType && $currentNodeName === $nodeName); + } + + /** + * @return string The name of the current node, un-prefixed + */ + public function getCurrentNodeName() + { + return $this->localName; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellHelper.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellHelper.php new file mode 100644 index 0000000000..6077839419 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellHelper.php @@ -0,0 +1,106 @@ + 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, + 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, + 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, + 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, + ]; + + /** + * Fills the missing indexes of an array with a given value. + * For instance, $dataArray = []; $a[1] = 1; $a[3] = 3; + * Calling fillMissingArrayIndexes($dataArray, 'FILL') will return this array: ['FILL', 1, 'FILL', 3] + * + * @param array $dataArray The array to fill + * @param string|void $fillValue optional + * @return array + */ + public static function fillMissingArrayIndexes($dataArray, $fillValue = '') + { + if (empty($dataArray)) { + return []; + } + $existingIndexes = array_keys($dataArray); + + $newIndexes = array_fill_keys(range(0, max($existingIndexes)), $fillValue); + $dataArray += $newIndexes; + + ksort($dataArray); + + return $dataArray; + } + + /** + * Returns the base 10 column index associated to the cell index (base 26). + * Excel uses A to Z letters for column indexing, where A is the 1st column, + * Z is the 26th and AA is the 27th. + * The mapping is zero based, so that A1 maps to 0, B2 maps to 1, Z13 to 25 and AA4 to 26. + * + * @param string $cellIndex The Excel cell index ('A1', 'BC13', ...) + * @return int + * @throws \Box\Spout\Common\Exception\InvalidArgumentException When the given cell index is invalid + */ + public static function getColumnIndexFromCellIndex($cellIndex) + { + if (!self::isValidCellIndex($cellIndex)) { + throw new InvalidArgumentException('Cannot get column index from an invalid cell index.'); + } + + $columnIndex = 0; + + // Remove row information + $columnLetters = preg_replace('/\d/', '', $cellIndex); + + // strlen() is super slow too... Using isset() is way faster and not too unreadable, + // since we checked before that there are between 1 and 3 letters. + $columnLength = isset($columnLetters[1]) ? (isset($columnLetters[2]) ? 3 : 2) : 1; + + // Looping over the different letters of the column is slower than this method. + // Also, not using the pow() function because it's slooooow... + switch ($columnLength) { + case 1: + $columnIndex = (self::$columnLetterToIndexMapping[$columnLetters]); + break; + case 2: + $firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 26; + $secondLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[1]]; + $columnIndex = $firstLetterIndex + $secondLetterIndex; + break; + case 3: + $firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 676; + $secondLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[1]] + 1) * 26; + $thirdLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[2]]; + $columnIndex = $firstLetterIndex + $secondLetterIndex + $thirdLetterIndex; + break; + } + + return $columnIndex; + } + + /** + * Returns whether a cell index is valid, in an Excel world. + * To be valid, the cell index should start with capital letters and be followed by numbers. + * There can only be 3 letters, as there can only be 16,384 rows, which is equivalent to 'XFE'. + * + * @param string $cellIndex The Excel cell index ('A1', 'BC13', ...) + * @return bool + */ + protected static function isValidCellIndex($cellIndex) + { + return (preg_match('/^[A-Z]{1,3}\d+$/', $cellIndex) === 1); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php new file mode 100644 index 0000000000..b4c625689c --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php @@ -0,0 +1,300 @@ +sharedStringsHelper = $sharedStringsHelper; + $this->styleHelper = $styleHelper; + $this->shouldFormatDates = $shouldFormatDates; + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->escaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); + } + + /** + * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node. + * + * @param \DOMNode $node + * @return string|int|float|bool|\DateTime|null The value associated with the cell (null when the cell has an error) + */ + public function extractAndFormatNodeValue($node) + { + // Default cell type is "n" + $cellType = $node->getAttribute(self::XML_ATTRIBUTE_TYPE) ?: self::CELL_TYPE_NUMERIC; + $cellStyleId = intval($node->getAttribute(self::XML_ATTRIBUTE_STYLE_ID)); + $vNodeValue = $this->getVNodeValue($node); + + if (($vNodeValue === '') && ($cellType !== self::CELL_TYPE_INLINE_STRING)) { + return $vNodeValue; + } + + switch ($cellType) { + case self::CELL_TYPE_INLINE_STRING: + return $this->formatInlineStringCellValue($node); + case self::CELL_TYPE_SHARED_STRING: + return $this->formatSharedStringCellValue($vNodeValue); + case self::CELL_TYPE_STR: + return $this->formatStrCellValue($vNodeValue); + case self::CELL_TYPE_BOOLEAN: + return $this->formatBooleanCellValue($vNodeValue); + case self::CELL_TYPE_NUMERIC: + return $this->formatNumericCellValue($vNodeValue, $cellStyleId); + case self::CELL_TYPE_DATE: + return $this->formatDateCellValue($vNodeValue); + default: + return null; + } + } + + /** + * Returns the cell's string value from a node's nested value node + * + * @param \DOMNode $node + * @return string The value associated with the cell + */ + protected function getVNodeValue($node) + { + // for cell types having a "v" tag containing the value. + // if not, the returned value should be empty string. + $vNode = $node->getElementsByTagName(self::XML_NODE_VALUE)->item(0); + return ($vNode !== null) ? $vNode->nodeValue : ''; + } + + /** + * Returns the cell String value where string is inline. + * + * @param \DOMNode $node + * @return string The value associated with the cell (null when the cell has an error) + */ + protected function formatInlineStringCellValue($node) + { + // inline strings are formatted this way: + // [INLINE_STRING] + $tNode = $node->getElementsByTagName(self::XML_NODE_INLINE_STRING_VALUE)->item(0); + $cellValue = $this->escaper->unescape($tNode->nodeValue); + return $cellValue; + } + + /** + * Returns the cell String value from shared-strings file using nodeValue index. + * + * @param string $nodeValue + * @return string The value associated with the cell (null when the cell has an error) + */ + protected function formatSharedStringCellValue($nodeValue) + { + // shared strings are formatted this way: + // [SHARED_STRING_INDEX] + $sharedStringIndex = intval($nodeValue); + $escapedCellValue = $this->sharedStringsHelper->getStringAtIndex($sharedStringIndex); + $cellValue = $this->escaper->unescape($escapedCellValue); + return $cellValue; + } + + /** + * Returns the cell String value, where string is stored in value node. + * + * @param string $nodeValue + * @return string The value associated with the cell (null when the cell has an error) + */ + protected function formatStrCellValue($nodeValue) + { + $escapedCellValue = trim($nodeValue); + $cellValue = $this->escaper->unescape($escapedCellValue); + return $cellValue; + } + + /** + * Returns the cell Numeric value from string of nodeValue. + * The value can also represent a timestamp and a DateTime will be returned. + * + * @param string $nodeValue + * @param int $cellStyleId 0 being the default style + * @return int|float|\DateTime|null The value associated with the cell + */ + protected function formatNumericCellValue($nodeValue, $cellStyleId) + { + // Numeric values can represent numbers as well as timestamps. + // We need to look at the style of the cell to determine whether it is one or the other. + $shouldFormatAsDate = $this->styleHelper->shouldFormatNumericValueAsDate($cellStyleId); + + if ($shouldFormatAsDate) { + return $this->formatExcelTimestampValue(floatval($nodeValue), $cellStyleId); + } else { + $nodeIntValue = intval($nodeValue); + return ($nodeIntValue == $nodeValue) ? $nodeIntValue : floatval($nodeValue); + } + } + + /** + * Returns a cell's PHP Date value, associated to the given timestamp. + * NOTE: The timestamp is a float representing the number of days since January 1st, 1900. + * NOTE: The timestamp can also represent a time, if it is a value between 0 and 1. + * + * @param float $nodeValue + * @param int $cellStyleId 0 being the default style + * @return \DateTime|null The value associated with the cell or NULL if invalid date value + */ + protected function formatExcelTimestampValue($nodeValue, $cellStyleId) + { + // Fix for the erroneous leap year in Excel + if (ceil($nodeValue) > self::ERRONEOUS_EXCEL_LEAP_YEAR_DAY) { + --$nodeValue; + } + + if ($nodeValue >= 1) { + // Values greater than 1 represent "dates". The value 1.0 representing the "base" date: 1900-01-01. + return $this->formatExcelTimestampValueAsDateValue($nodeValue, $cellStyleId); + } else if ($nodeValue >= 0) { + // Values between 0 and 1 represent "times". + return $this->formatExcelTimestampValueAsTimeValue($nodeValue, $cellStyleId); + } else { + // invalid date + return null; + } + } + + /** + * Returns a cell's PHP DateTime value, associated to the given timestamp. + * Only the time value matters. The date part is set to Jan 1st, 1900 (base Excel date). + * + * @param float $nodeValue + * @param int $cellStyleId 0 being the default style + * @return \DateTime|string The value associated with the cell + */ + protected function formatExcelTimestampValueAsTimeValue($nodeValue, $cellStyleId) + { + $time = round($nodeValue * self::NUM_SECONDS_IN_ONE_DAY); + $hours = floor($time / self::NUM_SECONDS_IN_ONE_HOUR); + $minutes = floor($time / self::NUM_SECONDS_IN_ONE_MINUTE) - ($hours * self::NUM_SECONDS_IN_ONE_MINUTE); + $seconds = $time - ($hours * self::NUM_SECONDS_IN_ONE_HOUR) - ($minutes * self::NUM_SECONDS_IN_ONE_MINUTE); + + // using the base Excel date (Jan 1st, 1900) - not relevant here + $dateObj = new \DateTime('1900-01-01'); + $dateObj->setTime($hours, $minutes, $seconds); + + if ($this->shouldFormatDates) { + $styleNumberFormatCode = $this->styleHelper->getNumberFormatCode($cellStyleId); + $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode); + return $dateObj->format($phpDateFormat); + } else { + return $dateObj; + } + } + + /** + * Returns a cell's PHP Date value, associated to the given timestamp. + * NOTE: The timestamp is a float representing the number of days since January 1st, 1900. + * + * @param float $nodeValue + * @param int $cellStyleId 0 being the default style + * @return \DateTime|string|null The value associated with the cell or NULL if invalid date value + */ + protected function formatExcelTimestampValueAsDateValue($nodeValue, $cellStyleId) + { + // Do not use any unix timestamps for calculation to prevent + // issues with numbers exceeding 2^31. + $secondsRemainder = fmod($nodeValue, 1) * self::NUM_SECONDS_IN_ONE_DAY; + $secondsRemainder = round($secondsRemainder, 0); + + try { + $dateObj = \DateTime::createFromFormat('|Y-m-d', '1899-12-31'); + $dateObj->modify('+' . intval($nodeValue) . 'days'); + $dateObj->modify('+' . $secondsRemainder . 'seconds'); + + if ($this->shouldFormatDates) { + $styleNumberFormatCode = $this->styleHelper->getNumberFormatCode($cellStyleId); + $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode); + return $dateObj->format($phpDateFormat); + } else { + return $dateObj; + } + } catch (\Exception $e) { + return null; + } + } + + /** + * Returns the cell Boolean value from a specific node's Value. + * + * @param string $nodeValue + * @return bool The value associated with the cell + */ + protected function formatBooleanCellValue($nodeValue) + { + // !! is similar to boolval() + $cellValue = !!$nodeValue; + return $cellValue; + } + + /** + * Returns a cell's PHP Date value, associated to the given stored nodeValue. + * @see ECMA-376 Part 1 - §18.17.4 + * + * @param string $nodeValue ISO 8601 Date string + * @return \DateTime|string|null The value associated with the cell or NULL if invalid date value + */ + protected function formatDateCellValue($nodeValue) + { + // Mitigate thrown Exception on invalid date-time format (http://php.net/manual/en/datetime.construct.php) + try { + return ($this->shouldFormatDates) ? $nodeValue : new \DateTime($nodeValue); + } catch (\Exception $e) { + return null; + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/DateFormatHelper.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/DateFormatHelper.php new file mode 100644 index 0000000000..9dba4c685a --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/DateFormatHelper.php @@ -0,0 +1,124 @@ + [ + // Time + 'am/pm' => 'A', // Uppercase Ante meridiem and Post meridiem + ':mm' => ':i', // Minutes with leading zeros - if preceded by a ":" (otherwise month) + 'mm:' => 'i:', // Minutes with leading zeros - if followed by a ":" (otherwise month) + 'ss' => 's', // Seconds, with leading zeros + '.s' => '', // Ignore (fractional seconds format does not exist in PHP) + + // Date + 'e' => 'Y', // Full numeric representation of a year, 4 digits + 'yyyy' => 'Y', // Full numeric representation of a year, 4 digits + 'yy' => 'y', // Two digit representation of a year + 'mmmmm' => 'M', // Short textual representation of a month, three letters ("mmmmm" should only contain the 1st letter...) + 'mmmm' => 'F', // Full textual representation of a month + 'mmm' => 'M', // Short textual representation of a month, three letters + 'mm' => 'm', // Numeric representation of a month, with leading zeros + 'm' => 'n', // Numeric representation of a month, without leading zeros + 'dddd' => 'l', // Full textual representation of the day of the week + 'ddd' => 'D', // Textual representation of a day, three letters + 'dd' => 'd', // Day of the month, 2 digits with leading zeros + 'd' => 'j', // Day of the month without leading zeros + ], + self::KEY_HOUR_12 => [ + 'hh' => 'h', // 12-hour format of an hour without leading zeros + 'h' => 'g', // 12-hour format of an hour without leading zeros + ], + self::KEY_HOUR_24 => [ + 'hh' => 'H', // 24-hour hours with leading zero + 'h' => 'G', // 24-hour format of an hour without leading zeros + ], + ]; + + /** + * Converts the given Excel date format to a format understandable by the PHP date function. + * + * @param string $excelDateFormat Excel date format + * @return string PHP date format (as defined here: http://php.net/manual/en/function.date.php) + */ + public static function toPHPDateFormat($excelDateFormat) + { + // Remove brackets potentially present at the beginning of the format string + // and text portion of the format at the end of it (starting with ";") + // See §18.8.31 of ECMA-376 for more detail. + $dateFormat = preg_replace('/^(?:\[\$[^\]]+?\])?([^;]*).*/', '$1', $excelDateFormat); + + // Double quotes are used to escape characters that must not be interpreted. + // For instance, ["Day " dd] should result in "Day 13" and we should not try to interpret "D", "a", "y" + // By exploding the format string using double quote as a delimiter, we can get all parts + // that must be transformed (even indexes) and all parts that must not be (odd indexes). + $dateFormatParts = explode('"', $dateFormat); + + foreach ($dateFormatParts as $partIndex => $dateFormatPart) { + // do not look at odd indexes + if ($partIndex % 2 === 1) { + continue; + } + + // Make sure all characters are lowercase, as the mapping table is using lowercase characters + $transformedPart = strtolower($dateFormatPart); + + // Remove escapes related to non-format characters + $transformedPart = str_replace('\\', '', $transformedPart); + + // Apply general transformation first... + $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_GENERAL]); + + // ... then apply hour transformation, for 12-hour or 24-hour format + if (self::has12HourFormatMarker($dateFormatPart)) { + $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_HOUR_12]); + } else { + $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_HOUR_24]); + } + + // overwrite the parts array with the new transformed part + $dateFormatParts[$partIndex] = $transformedPart; + } + + // Merge all transformed parts back together + $phpDateFormat = implode('"', $dateFormatParts); + + // Finally, to have the date format compatible with the DateTime::format() function, we need to escape + // all characters that are inside double quotes (and double quotes must be removed). + // For instance, ["Day " dd] should become [\D\a\y\ dd] + $phpDateFormat = preg_replace_callback('/"(.+?)"/', function($matches) { + $stringToEscape = $matches[1]; + $letters = preg_split('//u', $stringToEscape, -1, PREG_SPLIT_NO_EMPTY); + return '\\' . implode('\\', $letters); + }, $phpDateFormat); + + return $phpDateFormat; + } + + /** + * @param string $excelDateFormat Date format as defined by Excel + * @return bool Whether the given date format has the 12-hour format marker + */ + private static function has12HourFormatMarker($excelDateFormat) + { + return (stripos($excelDateFormat, 'am/pm') !== false); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyFactory.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyFactory.php new file mode 100644 index 0000000000..36e0bfef0b --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyFactory.php @@ -0,0 +1,159 @@ + 20 * 600 ≈ 12KB + */ + const AMOUNT_MEMORY_NEEDED_PER_STRING_IN_KB = 12; + + /** + * To avoid running out of memory when extracting a huge number of shared strings, they can be saved to temporary files + * instead of in memory. Then, when accessing a string, the corresponding file contents will be loaded in memory + * and the string will be quickly retrieved. + * The performance bottleneck is not when creating these temporary files, but rather when loading their content. + * Because the contents of the last loaded file stays in memory until another file needs to be loaded, it works + * best when the indexes of the shared strings are sorted in the sheet data. + * 10,000 was chosen because it creates small files that are fast to be loaded in memory. + */ + const MAX_NUM_STRINGS_PER_TEMP_FILE = 10000; + + /** @var CachingStrategyFactory|null Singleton instance */ + protected static $instance = null; + + /** + * Private constructor for singleton + */ + private function __construct() + { + } + + /** + * Returns the singleton instance of the factory + * + * @return CachingStrategyFactory + */ + public static function getInstance() + { + if (self::$instance === null) { + self::$instance = new CachingStrategyFactory(); + } + + return self::$instance; + } + + /** + * Returns the best caching strategy, given the number of unique shared strings + * and the amount of memory available. + * + * @param int|null $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown) + * @param string|void $tempFolder Temporary folder where the temporary files to store shared strings will be stored + * @return CachingStrategyInterface The best caching strategy + */ + public function getBestCachingStrategy($sharedStringsUniqueCount, $tempFolder = null) + { + if ($this->isInMemoryStrategyUsageSafe($sharedStringsUniqueCount)) { + return new InMemoryStrategy($sharedStringsUniqueCount); + } else { + return new FileBasedStrategy($tempFolder, self::MAX_NUM_STRINGS_PER_TEMP_FILE); + } + } + + /** + * Returns whether it is safe to use in-memory caching, given the number of unique shared strings + * and the amount of memory available. + * + * @param int|null $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown) + * @return bool + */ + protected function isInMemoryStrategyUsageSafe($sharedStringsUniqueCount) + { + // if the number of shared strings in unknown, do not use "in memory" strategy + if ($sharedStringsUniqueCount === null) { + return false; + } + + $memoryAvailable = $this->getMemoryLimitInKB(); + + if ($memoryAvailable === -1) { + // if cannot get memory limit or if memory limit set as unlimited, don't trust and play safe + return ($sharedStringsUniqueCount < self::MAX_NUM_STRINGS_PER_TEMP_FILE); + } else { + $memoryNeeded = $sharedStringsUniqueCount * self::AMOUNT_MEMORY_NEEDED_PER_STRING_IN_KB; + return ($memoryAvailable > $memoryNeeded); + } + } + + /** + * Returns the PHP "memory_limit" in Kilobytes + * + * @return float + */ + protected function getMemoryLimitInKB() + { + $memoryLimitFormatted = $this->getMemoryLimitFromIni(); + $memoryLimitFormatted = strtolower(trim($memoryLimitFormatted)); + + // No memory limit + if ($memoryLimitFormatted === '-1') { + return -1; + } + + if (preg_match('/(\d+)([bkmgt])b?/', $memoryLimitFormatted, $matches)) { + $amount = intval($matches[1]); + $unit = $matches[2]; + + switch ($unit) { + case 'b': return ($amount / 1024); + case 'k': return $amount; + case 'm': return ($amount * 1024); + case 'g': return ($amount * 1024 * 1024); + case 't': return ($amount * 1024 * 1024 * 1024); + } + } + + return -1; + } + + /** + * Returns the formatted "memory_limit" value + * + * @return string + */ + protected function getMemoryLimitFromIni() + { + return ini_get('memory_limit'); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyInterface.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyInterface.php new file mode 100644 index 0000000000..631222a321 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/CachingStrategyInterface.php @@ -0,0 +1,44 @@ +fileSystemHelper = new FileSystemHelper($rootTempFolder); + $this->tempFolder = $this->fileSystemHelper->createFolder($rootTempFolder, uniqid('sharedstrings')); + + $this->maxNumStringsPerTempFile = $maxNumStringsPerTempFile; + + $this->globalFunctionsHelper = new GlobalFunctionsHelper(); + $this->tempFilePointer = null; + } + + /** + * Adds the given string to the cache. + * + * @param string $sharedString The string to be added to the cache + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return void + */ + public function addStringForIndex($sharedString, $sharedStringIndex) + { + $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex); + + if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) { + if ($this->tempFilePointer) { + $this->globalFunctionsHelper->fclose($this->tempFilePointer); + } + $this->tempFilePointer = $this->globalFunctionsHelper->fopen($tempFilePath, 'w'); + } + + // The shared string retrieval logic expects each cell data to be on one line only + // Encoding the line feed character allows to preserve this assumption + $lineFeedEncodedSharedString = $this->escapeLineFeed($sharedString); + + $this->globalFunctionsHelper->fwrite($this->tempFilePointer, $lineFeedEncodedSharedString . PHP_EOL); + } + + /** + * Returns the path for the temp file that should contain the string for the given index + * + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return string The temp file path for the given index + */ + protected function getSharedStringTempFilePath($sharedStringIndex) + { + $numTempFile = intval($sharedStringIndex / $this->maxNumStringsPerTempFile); + return $this->tempFolder . '/sharedstrings' . $numTempFile; + } + + /** + * Closes the cache after the last shared string was added. + * This prevents any additional string from being added to the cache. + * + * @return void + */ + public function closeCache() + { + // close pointer to the last temp file that was written + if ($this->tempFilePointer) { + $this->globalFunctionsHelper->fclose($this->tempFilePointer); + } + } + + + /** + * Returns the string located at the given index from the cache. + * + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return string The shared string at the given index + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index + */ + public function getStringAtIndex($sharedStringIndex) + { + $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex); + $indexInFile = $sharedStringIndex % $this->maxNumStringsPerTempFile; + + if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) { + throw new SharedStringNotFoundException("Shared string temp file not found: $tempFilePath ; for index: $sharedStringIndex"); + } + + if ($this->inMemoryTempFilePath !== $tempFilePath) { + // free memory + unset($this->inMemoryTempFileContents); + + $this->inMemoryTempFileContents = explode(PHP_EOL, $this->globalFunctionsHelper->file_get_contents($tempFilePath)); + $this->inMemoryTempFilePath = $tempFilePath; + } + + $sharedString = null; + + // Using isset here because it is way faster than array_key_exists... + if (isset($this->inMemoryTempFileContents[$indexInFile])) { + $escapedSharedString = $this->inMemoryTempFileContents[$indexInFile]; + $sharedString = $this->unescapeLineFeed($escapedSharedString); + } + + if ($sharedString === null) { + throw new SharedStringNotFoundException("Shared string not found for index: $sharedStringIndex"); + } + + return rtrim($sharedString, PHP_EOL); + } + + /** + * Escapes the line feed characters (\n) + * + * @param string $unescapedString + * @return string + */ + private function escapeLineFeed($unescapedString) + { + return str_replace("\n", self::ESCAPED_LINE_FEED_CHARACTER, $unescapedString); + } + + /** + * Unescapes the line feed characters (\n) + * + * @param string $escapedString + * @return string + */ + private function unescapeLineFeed($escapedString) + { + return str_replace(self::ESCAPED_LINE_FEED_CHARACTER, "\n", $escapedString); + } + + /** + * Destroys the cache, freeing memory and removing any created artifacts + * + * @return void + */ + public function clearCache() + { + if ($this->tempFolder) { + $this->fileSystemHelper->deleteFolderRecursively($this->tempFolder); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/InMemoryStrategy.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/InMemoryStrategy.php new file mode 100644 index 0000000000..c6a5321a55 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsCaching/InMemoryStrategy.php @@ -0,0 +1,83 @@ +inMemoryCache = new \SplFixedArray($sharedStringsUniqueCount); + $this->isCacheClosed = false; + } + + /** + * Adds the given string to the cache. + * + * @param string $sharedString The string to be added to the cache + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return void + */ + public function addStringForIndex($sharedString, $sharedStringIndex) + { + if (!$this->isCacheClosed) { + $this->inMemoryCache->offsetSet($sharedStringIndex, $sharedString); + } + } + + /** + * Closes the cache after the last shared string was added. + * This prevents any additional string from being added to the cache. + * + * @return void + */ + public function closeCache() + { + $this->isCacheClosed = true; + } + + /** + * Returns the string located at the given index from the cache. + * + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return string The shared string at the given index + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index + */ + public function getStringAtIndex($sharedStringIndex) + { + try { + return $this->inMemoryCache->offsetGet($sharedStringIndex); + } catch (\RuntimeException $e) { + throw new SharedStringNotFoundException("Shared string not found for index: $sharedStringIndex"); + } + } + + /** + * Destroys the cache, freeing memory and removing any created artifacts + * + * @return void + */ + public function clearCache() + { + unset($this->inMemoryCache); + $this->isCacheClosed = false; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsHelper.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsHelper.php new file mode 100644 index 0000000000..fc04c794dc --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SharedStringsHelper.php @@ -0,0 +1,234 @@ +filePath = $filePath; + $this->tempFolder = $tempFolder; + } + + /** + * Returns whether the XLSX file contains a shared strings XML file + * + * @return bool + */ + public function hasSharedStrings() + { + $hasSharedStrings = false; + $zip = new \ZipArchive(); + + if ($zip->open($this->filePath) === true) { + $hasSharedStrings = ($zip->locateName(self::SHARED_STRINGS_XML_FILE_PATH) !== false); + $zip->close(); + } + + return $hasSharedStrings; + } + + /** + * Builds an in-memory array containing all the shared strings of the sheet. + * All the strings are stored in a XML file, located at 'xl/sharedStrings.xml'. + * It is then accessed by the sheet data, via the string index in the built table. + * + * More documentation available here: http://msdn.microsoft.com/en-us/library/office/gg278314.aspx + * + * The XML file can be really big with sheets containing a lot of data. That is why + * we need to use a XML reader that provides streaming like the XMLReader library. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If sharedStrings.xml can't be read + */ + public function extractSharedStrings() + { + $xmlReader = new XMLReader(); + $sharedStringIndex = 0; + + if ($xmlReader->openFileInZip($this->filePath, self::SHARED_STRINGS_XML_FILE_PATH) === false) { + throw new IOException('Could not open "' . self::SHARED_STRINGS_XML_FILE_PATH . '".'); + } + + try { + $sharedStringsUniqueCount = $this->getSharedStringsUniqueCount($xmlReader); + $this->cachingStrategy = $this->getBestSharedStringsCachingStrategy($sharedStringsUniqueCount); + + $xmlReader->readUntilNodeFound(self::XML_NODE_SI); + + while ($xmlReader->getCurrentNodeName() === self::XML_NODE_SI) { + $this->processSharedStringsItem($xmlReader, $sharedStringIndex); + $sharedStringIndex++; + + // jump to the next '' tag + $xmlReader->next(self::XML_NODE_SI); + } + + $this->cachingStrategy->closeCache(); + + } catch (XMLProcessingException $exception) { + throw new IOException("The sharedStrings.xml file is invalid and cannot be read. [{$exception->getMessage()}]"); + } + + $xmlReader->close(); + } + + /** + * Returns the shared strings unique count, as specified in tag. + * + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader instance + * @return int|null Number of unique shared strings in the sharedStrings.xml file + * @throws \Box\Spout\Common\Exception\IOException If sharedStrings.xml is invalid and can't be read + */ + protected function getSharedStringsUniqueCount($xmlReader) + { + $xmlReader->next(self::XML_NODE_SST); + + // Iterate over the "sst" elements to get the actual "sst ELEMENT" (skips any DOCTYPE) + while ($xmlReader->getCurrentNodeName() === self::XML_NODE_SST && $xmlReader->nodeType !== XMLReader::ELEMENT) { + $xmlReader->read(); + } + + $uniqueCount = $xmlReader->getAttribute(self::XML_ATTRIBUTE_UNIQUE_COUNT); + + // some software do not add the "uniqueCount" attribute but only use the "count" one + // @see https://github.com/box/spout/issues/254 + if ($uniqueCount === null) { + $uniqueCount = $xmlReader->getAttribute(self::XML_ATTRIBUTE_COUNT); + } + + return ($uniqueCount !== null) ? intval($uniqueCount) : null; + } + + /** + * Returns the best shared strings caching strategy. + * + * @param int|null $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown) + * @return CachingStrategyInterface + */ + protected function getBestSharedStringsCachingStrategy($sharedStringsUniqueCount) + { + return CachingStrategyFactory::getInstance() + ->getBestCachingStrategy($sharedStringsUniqueCount, $this->tempFolder); + } + + /** + * Processes the shared strings item XML node which the given XML reader is positioned on. + * + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on a "" node + * @param int $sharedStringIndex Index of the processed shared strings item + * @return void + */ + protected function processSharedStringsItem($xmlReader, $sharedStringIndex) + { + $sharedStringValue = ''; + + // NOTE: expand() will automatically decode all XML entities of the child nodes + $siNode = $xmlReader->expand(); + $textNodes = $siNode->getElementsByTagName(self::XML_NODE_T); + + foreach ($textNodes as $textNode) { + if ($this->shouldExtractTextNodeValue($textNode)) { + $textNodeValue = $textNode->nodeValue; + $shouldPreserveWhitespace = $this->shouldPreserveWhitespace($textNode); + + $sharedStringValue .= ($shouldPreserveWhitespace) ? $textNodeValue : trim($textNodeValue); + } + } + + $this->cachingStrategy->addStringForIndex($sharedStringValue, $sharedStringIndex); + } + + /** + * Not all text nodes' values must be extracted. + * Some text nodes are part of a node describing the pronunciation for instance. + * We'll only consider the nodes whose parents are "" or "". + * + * @param \DOMElement $textNode Text node to check + * @return bool Whether the given text node's value must be extracted + */ + protected function shouldExtractTextNodeValue($textNode) + { + $parentTagName = $textNode->parentNode->localName; + return ($parentTagName === self::XML_NODE_SI || $parentTagName === self::XML_NODE_R); + } + + /** + * If the text node has the attribute 'xml:space="preserve"', then preserve whitespace. + * + * @param \DOMElement $textNode The text node element () whose whitespace may be preserved + * @return bool Whether whitespace should be preserved + */ + protected function shouldPreserveWhitespace($textNode) + { + $spaceValue = $textNode->getAttribute(self::XML_ATTRIBUTE_XML_SPACE); + return ($spaceValue === self::XML_ATTRIBUTE_VALUE_PRESERVE); + } + + /** + * Returns the shared string at the given index, using the previously chosen caching strategy. + * + * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file + * @return string The shared string at the given index + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index + */ + public function getStringAtIndex($sharedStringIndex) + { + return $this->cachingStrategy->getStringAtIndex($sharedStringIndex); + } + + /** + * Destroys the cache, freeing memory and removing any created artifacts + * + * @return void + */ + public function cleanup() + { + if ($this->cachingStrategy) { + $this->cachingStrategy->clearCache(); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SheetHelper.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SheetHelper.php new file mode 100644 index 0000000000..b74ba01bc3 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/SheetHelper.php @@ -0,0 +1,156 @@ +filePath = $filePath; + $this->options = $options; + $this->sharedStringsHelper = $sharedStringsHelper; + $this->globalFunctionsHelper = $globalFunctionsHelper; + } + + /** + * Returns the sheets metadata of the file located at the previously given file path. + * The paths to the sheets' data are read from the [Content_Types].xml file. + * + * @return Sheet[] Sheets within the XLSX file + */ + public function getSheets() + { + $sheets = []; + $sheetIndex = 0; + $activeSheetIndex = 0; // By default, the first sheet is active + + $xmlReader = new XMLReader(); + if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_FILE_PATH)) { + while ($xmlReader->read()) { + if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_WORKBOOK_VIEW)) { + // The "workbookView" node is located before "sheet" nodes, ensuring that + // the active sheet is known before parsing sheets data. + $activeSheetIndex = (int) $xmlReader->getAttribute(self::XML_ATTRIBUTE_ACTIVE_TAB); + } else if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_SHEET)) { + $isSheetActive = ($sheetIndex === $activeSheetIndex); + $sheets[] = $this->getSheetFromSheetXMLNode($xmlReader, $sheetIndex, $isSheetActive); + $sheetIndex++; + } else if ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_SHEETS)) { + // stop reading once all sheets have been read + break; + } + } + + $xmlReader->close(); + } + + return $sheets; + } + + /** + * Returns an instance of a sheet, given the XML node describing the sheet - from "workbook.xml". + * We can find the XML file path describing the sheet inside "workbook.xml.res", by mapping with the sheet ID + * ("r:id" in "workbook.xml", "Id" in "workbook.xml.res"). + * + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReaderOnSheetNode XML Reader instance, pointing on the node describing the sheet, as defined in "workbook.xml" + * @param int $sheetIndexZeroBased Index of the sheet, based on order of appearance in the workbook (zero-based) + * @param bool $isSheetActive Whether this sheet was defined as active + * @return \Box\Spout\Reader\XLSX\Sheet Sheet instance + */ + protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive) + { + $sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID); + $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME); + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $escaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); + $sheetName = $escaper->unescape($escapedSheetName); + + $sheetDataXMLFilePath = $this->getSheetDataXMLFilePathForSheetId($sheetId); + + return new Sheet( + $this->filePath, $sheetDataXMLFilePath, + $sheetIndexZeroBased, $sheetName, $isSheetActive, + $this->options, $this->sharedStringsHelper + ); + } + + /** + * @param string $sheetId The sheet ID, as defined in "workbook.xml" + * @return string The XML file path describing the sheet inside "workbook.xml.res", for the given sheet ID + */ + protected function getSheetDataXMLFilePathForSheetId($sheetId) + { + $sheetDataXMLFilePath = ''; + + // find the file path of the sheet, by looking at the "workbook.xml.res" file + $xmlReader = new XMLReader(); + if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_RELS_FILE_PATH)) { + while ($xmlReader->read()) { + if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_RELATIONSHIP)) { + $relationshipSheetId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_ID); + + if ($relationshipSheetId === $sheetId) { + // In workbook.xml.rels, it is only "worksheets/sheet1.xml" + // In [Content_Types].xml, the path is "/xl/worksheets/sheet1.xml" + $sheetDataXMLFilePath = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET); + + // sometimes, the sheet data file path already contains "/xl/"... + if (strpos($sheetDataXMLFilePath, '/xl/') !== 0) { + $sheetDataXMLFilePath = '/xl/' . $sheetDataXMLFilePath; + break; + } + } + } + } + + $xmlReader->close(); + } + + return $sheetDataXMLFilePath; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/StyleHelper.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/StyleHelper.php new file mode 100644 index 0000000000..000adab887 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Helper/StyleHelper.php @@ -0,0 +1,330 @@ + 'm/d/yyyy', // @NOTE: ECMA spec is 'mm-dd-yy' + 15 => 'd-mmm-yy', + 16 => 'd-mmm', + 17 => 'mmm-yy', + 18 => 'h:mm AM/PM', + 19 => 'h:mm:ss AM/PM', + 20 => 'h:mm', + 21 => 'h:mm:ss', + 22 => 'm/d/yyyy h:mm', // @NOTE: ECMA spec is 'm/d/yy h:mm', + 45 => 'mm:ss', + 46 => '[h]:mm:ss', + 47 => 'mm:ss.0', // @NOTE: ECMA spec is 'mmss.0', + ]; + + /** @var string Path of the XLSX file being read */ + protected $filePath; + + /** @var array Array containing the IDs of built-in number formats indicating a date */ + protected $builtinNumFmtIdIndicatingDates; + + /** @var array Array containing a mapping NUM_FMT_ID => FORMAT_CODE */ + protected $customNumberFormats; + + /** @var array Array containing a mapping STYLE_ID => [STYLE_ATTRIBUTES] */ + protected $stylesAttributes; + + /** @var array Cache containing a mapping NUM_FMT_ID => IS_DATE_FORMAT. Used to avoid lots of recalculations */ + protected $numFmtIdToIsDateFormatCache = []; + + /** + * @param string $filePath Path of the XLSX file being read + */ + public function __construct($filePath) + { + $this->filePath = $filePath; + $this->builtinNumFmtIdIndicatingDates = array_keys(self::$builtinNumFmtIdToNumFormatMapping); + } + + /** + * Returns whether the style with the given ID should consider + * numeric values as timestamps and format the cell as a date. + * + * @param int $styleId Zero-based style ID + * @return bool Whether the cell with the given cell should display a date instead of a numeric value + */ + public function shouldFormatNumericValueAsDate($styleId) + { + $stylesAttributes = $this->getStylesAttributes(); + + // Default style (0) does not format numeric values as timestamps. Only custom styles do. + // Also if the style ID does not exist in the styles.xml file, format as numeric value. + // Using isset here because it is way faster than array_key_exists... + if ($styleId === self::DEFAULT_STYLE_ID || !isset($stylesAttributes[$styleId])) { + return false; + } + + $styleAttributes = $stylesAttributes[$styleId]; + + return $this->doesStyleIndicateDate($styleAttributes); + } + + /** + * Reads the styles.xml file and extract the relevant information from the file. + * + * @return void + */ + protected function extractRelevantInfo() + { + $this->customNumberFormats = []; + $this->stylesAttributes = []; + + $xmlReader = new XMLReader(); + + if ($xmlReader->openFileInZip($this->filePath, self::STYLES_XML_FILE_PATH)) { + while ($xmlReader->read()) { + if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_NUM_FMTS)) { + $this->extractNumberFormats($xmlReader); + + } else if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_CELL_XFS)) { + $this->extractStyleAttributes($xmlReader); + } + } + + $xmlReader->close(); + } + } + + /** + * Extracts number formats from the "numFmt" nodes. + * For simplicity, the styles attributes are kept in memory. This is possible thanks + * to the reuse of formats. So 1 million cells should not use 1 million formats. + * + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on the "numFmts" node + * @return void + */ + protected function extractNumberFormats($xmlReader) + { + while ($xmlReader->read()) { + if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_NUM_FMT)) { + $numFmtId = intval($xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID)); + $formatCode = $xmlReader->getAttribute(self::XML_ATTRIBUTE_FORMAT_CODE); + $this->customNumberFormats[$numFmtId] = $formatCode; + } else if ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_NUM_FMTS)) { + // Once done reading "numFmts" node's children + break; + } + } + } + + /** + * Extracts style attributes from the "xf" nodes, inside the "cellXfs" section. + * For simplicity, the styles attributes are kept in memory. This is possible thanks + * to the reuse of styles. So 1 million cells should not use 1 million styles. + * + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on the "cellXfs" node + * @return void + */ + protected function extractStyleAttributes($xmlReader) + { + while ($xmlReader->read()) { + if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_XF)) { + $numFmtId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID); + $normalizedNumFmtId = ($numFmtId !== null) ? intval($numFmtId) : null; + + $applyNumberFormat = $xmlReader->getAttribute(self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT); + $normalizedApplyNumberFormat = ($applyNumberFormat !== null) ? !!$applyNumberFormat : null; + + $this->stylesAttributes[] = [ + self::XML_ATTRIBUTE_NUM_FMT_ID => $normalizedNumFmtId, + self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT => $normalizedApplyNumberFormat, + ]; + } else if ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_CELL_XFS)) { + // Once done reading "cellXfs" node's children + break; + } + } + } + + /** + * @return array The custom number formats + */ + protected function getCustomNumberFormats() + { + if (!isset($this->customNumberFormats)) { + $this->extractRelevantInfo(); + } + + return $this->customNumberFormats; + } + + /** + * @return array The styles attributes + */ + protected function getStylesAttributes() + { + if (!isset($this->stylesAttributes)) { + $this->extractRelevantInfo(); + } + + return $this->stylesAttributes; + } + + /** + * @param array $styleAttributes Array containing the style attributes (2 keys: "applyNumberFormat" and "numFmtId") + * @return bool Whether the style with the given attributes indicates that the number is a date + */ + protected function doesStyleIndicateDate($styleAttributes) + { + $applyNumberFormat = $styleAttributes[self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT]; + $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID]; + + // A style may apply a date format if it has: + // - "applyNumberFormat" attribute not set to "false" + // - "numFmtId" attribute set + // This is a preliminary check, as having "numFmtId" set just means the style should apply a specific number format, + // but this is not necessarily a date. + if ($applyNumberFormat === false || $numFmtId === null) { + return false; + } + + return $this->doesNumFmtIdIndicateDate($numFmtId); + } + + /** + * Returns whether the number format ID indicates that the number is a date. + * The result is cached to avoid recomputing the same thing over and over, as + * "numFmtId" attributes can be shared between multiple styles. + * + * @param int $numFmtId + * @return bool Whether the number format ID indicates that the number is a date + */ + protected function doesNumFmtIdIndicateDate($numFmtId) + { + if (!isset($this->numFmtIdToIsDateFormatCache[$numFmtId])) { + $formatCode = $this->getFormatCodeForNumFmtId($numFmtId); + + $this->numFmtIdToIsDateFormatCache[$numFmtId] = ( + $this->isNumFmtIdBuiltInDateFormat($numFmtId) || + $this->isFormatCodeCustomDateFormat($formatCode) + ); + } + + return $this->numFmtIdToIsDateFormatCache[$numFmtId]; + } + + /** + * @param int $numFmtId + * @return string|null The custom number format or NULL if none defined for the given numFmtId + */ + protected function getFormatCodeForNumFmtId($numFmtId) + { + $customNumberFormats = $this->getCustomNumberFormats(); + + // Using isset here because it is way faster than array_key_exists... + return (isset($customNumberFormats[$numFmtId])) ? $customNumberFormats[$numFmtId] : null; + } + + /** + * @param int $numFmtId + * @return bool Whether the number format ID indicates that the number is a date + */ + protected function isNumFmtIdBuiltInDateFormat($numFmtId) + { + return in_array($numFmtId, $this->builtinNumFmtIdIndicatingDates); + } + + /** + * @param string|null $formatCode + * @return bool Whether the given format code indicates that the number is a date + */ + protected function isFormatCodeCustomDateFormat($formatCode) + { + // if no associated format code or if using the default "General" format + if ($formatCode === null || strcasecmp($formatCode, self::NUMBER_FORMAT_GENERAL) === 0) { + return false; + } + + return $this->isFormatCodeMatchingDateFormatPattern($formatCode); + } + + /** + * @param string $formatCode + * @return bool Whether the given format code matches a date format pattern + */ + protected function isFormatCodeMatchingDateFormatPattern($formatCode) + { + // Remove extra formatting (what's between [ ], the brackets should not be preceded by a "\") + $pattern = '((?getStylesAttributes(); + $styleAttributes = $stylesAttributes[$styleId]; + $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID]; + + if ($this->isNumFmtIdBuiltInDateFormat($numFmtId)) { + $numberFormatCode = self::$builtinNumFmtIdToNumFormatMapping[$numFmtId]; + } else { + $customNumberFormats = $this->getCustomNumberFormats(); + $numberFormatCode = $customNumberFormats[$numFmtId]; + } + + return $numberFormatCode; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Reader.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Reader.php new file mode 100644 index 0000000000..76e8e325cf --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Reader.php @@ -0,0 +1,113 @@ +options)) { + $this->options = new ReaderOptions(); + } + return $this->options; + } + + /** + * @param string $tempFolder Temporary folder where the temporary files will be created + * @return Reader + */ + public function setTempFolder($tempFolder) + { + $this->getOptions()->setTempFolder($tempFolder); + return $this; + } + + /** + * Returns whether stream wrappers are supported + * + * @return bool + */ + protected function doesSupportStreamWrapper() + { + return false; + } + + /** + * Opens the file at the given file path to make it ready to be read. + * It also parses the sharedStrings.xml file to get all the shared strings available in memory + * and fetches all the available sheets. + * + * @param string $filePath Path of the file to be read + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the file at the given path or its content cannot be read + * @throws \Box\Spout\Reader\Exception\NoSheetsFoundException If there are no sheets in the file + */ + protected function openReader($filePath) + { + $this->zip = new \ZipArchive(); + + if ($this->zip->open($filePath) === true) { + $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->getOptions()->getTempFolder()); + + if ($this->sharedStringsHelper->hasSharedStrings()) { + // Extracts all the strings from the sheets for easy access in the future + $this->sharedStringsHelper->extractSharedStrings(); + } + + $this->sheetIterator = new SheetIterator($filePath, $this->getOptions(), $this->sharedStringsHelper, $this->globalFunctionsHelper); + } else { + throw new IOException("Could not open $filePath for reading."); + } + } + + /** + * Returns an iterator to iterate over sheets. + * + * @return SheetIterator To iterate over sheets + */ + protected function getConcreteSheetIterator() + { + return $this->sheetIterator; + } + + /** + * Closes the reader. To be used after reading the file. + * + * @return void + */ + protected function closeReader() + { + if ($this->zip) { + $this->zip->close(); + } + + if ($this->sharedStringsHelper) { + $this->sharedStringsHelper->cleanup(); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/ReaderOptions.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/ReaderOptions.php new file mode 100644 index 0000000000..5f78c5d280 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/ReaderOptions.php @@ -0,0 +1,33 @@ +tempFolder; + } + + /** + * @param string|null $tempFolder Temporary folder where the temporary files will be created + * @return ReaderOptions + */ + public function setTempFolder($tempFolder) + { + $this->tempFolder = $tempFolder; + return $this; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/RowIterator.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/RowIterator.php new file mode 100644 index 0000000000..e70c617433 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/RowIterator.php @@ -0,0 +1,405 @@ +filePath = $filePath; + $this->sheetDataXMLFilePath = $this->normalizeSheetDataXMLFilePath($sheetDataXMLFilePath); + + $this->xmlReader = new XMLReader(); + + $this->styleHelper = new StyleHelper($filePath); + $this->cellValueFormatter = new CellValueFormatter($sharedStringsHelper, $this->styleHelper, $options->shouldFormatDates()); + + $this->shouldPreserveEmptyRows = $options->shouldPreserveEmptyRows(); + + // Register all callbacks to process different nodes when reading the XML file + $this->xmlProcessor = new XMLProcessor($this->xmlReader); + $this->xmlProcessor->registerCallback(self::XML_NODE_DIMENSION, XMLProcessor::NODE_TYPE_START, [$this, 'processDimensionStartingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_START, [$this, 'processRowStartingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_CELL, XMLProcessor::NODE_TYPE_START, [$this, 'processCellStartingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_END, [$this, 'processRowEndingNode']); + $this->xmlProcessor->registerCallback(self::XML_NODE_WORKSHEET, XMLProcessor::NODE_TYPE_END, [$this, 'processWorksheetEndingNode']); + } + + /** + * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml + * @return string Path of the XML file containing the sheet data, + * without the leading slash. + */ + protected function normalizeSheetDataXMLFilePath($sheetDataXMLFilePath) + { + return ltrim($sheetDataXMLFilePath, '/'); + } + + /** + * Rewind the Iterator to the first element. + * Initializes the XMLReader object that reads the associated sheet data. + * The XMLReader is configured to be safe from billion laughs attack. + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data XML cannot be read + */ + public function rewind() + { + $this->xmlReader->close(); + + if ($this->xmlReader->openFileInZip($this->filePath, $this->sheetDataXMLFilePath) === false) { + throw new IOException("Could not open \"{$this->sheetDataXMLFilePath}\"."); + } + + $this->numReadRows = 0; + $this->lastRowIndexProcessed = 0; + $this->nextRowIndexToBeProcessed = 0; + $this->rowDataBuffer = null; + $this->hasReachedEndOfFile = false; + $this->numColumns = 0; + + $this->next(); + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return (!$this->hasReachedEndOfFile); + } + + /** + * Move forward to next element. Reads data describing the next unprocessed row. + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If a shared string was not found + * @throws \Box\Spout\Common\Exception\IOException If unable to read the sheet data XML + */ + public function next() + { + $this->nextRowIndexToBeProcessed++; + + if ($this->doesNeedDataForNextRowToBeProcessed()) { + $this->readDataForNextRow(); + } + } + + /** + * Returns whether we need data for the next row to be processed. + * We don't need to read data if: + * we have already read at least one row + * AND + * we need to preserve empty rows + * AND + * the last row that was read is not the row that need to be processed + * (i.e. if we need to return empty rows) + * + * @return bool Whether we need data for the next row to be processed. + */ + protected function doesNeedDataForNextRowToBeProcessed() + { + $hasReadAtLeastOneRow = ($this->lastRowIndexProcessed !== 0); + + return ( + !$hasReadAtLeastOneRow || + !$this->shouldPreserveEmptyRows || + $this->lastRowIndexProcessed < $this->nextRowIndexToBeProcessed + ); + } + + /** + * @return void + * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If a shared string was not found + * @throws \Box\Spout\Common\Exception\IOException If unable to read the sheet data XML + */ + protected function readDataForNextRow() + { + $this->currentlyProcessedRowData = []; + + try { + $this->xmlProcessor->readUntilStopped(); + } catch (XMLProcessingException $exception) { + throw new IOException("The {$this->sheetDataXMLFilePath} file cannot be read. [{$exception->getMessage()}]"); + } + + $this->rowDataBuffer = $this->currentlyProcessedRowData; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int A return code that indicates what action should the processor take next + */ + protected function processDimensionStartingNode($xmlReader) + { + // Read dimensions of the sheet + $dimensionRef = $xmlReader->getAttribute(self::XML_ATTRIBUTE_REF); // returns 'A1:M13' for instance (or 'A1' for empty sheet) + if (preg_match('/[A-Z]+\d+:([A-Z]+\d+)/', $dimensionRef, $matches)) { + $this->numColumns = CellHelper::getColumnIndexFromCellIndex($matches[1]) + 1; + } + + return XMLProcessor::PROCESSING_CONTINUE; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int A return code that indicates what action should the processor take next + */ + protected function processRowStartingNode($xmlReader) + { + // Reset index of the last processed column + $this->lastColumnIndexProcessed = -1; + + // Mark the last processed row as the one currently being read + $this->lastRowIndexProcessed = $this->getRowIndex($xmlReader); + + // Read spans info if present + $numberOfColumnsForRow = $this->numColumns; + $spans = $xmlReader->getAttribute(self::XML_ATTRIBUTE_SPANS); // returns '1:5' for instance + if ($spans) { + list(, $numberOfColumnsForRow) = explode(':', $spans); + $numberOfColumnsForRow = intval($numberOfColumnsForRow); + } + + $this->currentlyProcessedRowData = ($numberOfColumnsForRow !== 0) ? array_fill(0, $numberOfColumnsForRow, '') : []; + + return XMLProcessor::PROCESSING_CONTINUE; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node + * @return int A return code that indicates what action should the processor take next + */ + protected function processCellStartingNode($xmlReader) + { + $currentColumnIndex = $this->getColumnIndex($xmlReader); + + // NOTE: expand() will automatically decode all XML entities of the child nodes + $node = $xmlReader->expand(); + $this->currentlyProcessedRowData[$currentColumnIndex] = $this->getCellValue($node); + $this->lastColumnIndexProcessed = $currentColumnIndex; + + return XMLProcessor::PROCESSING_CONTINUE; + } + + /** + * @return int A return code that indicates what action should the processor take next + */ + protected function processRowEndingNode() + { + // if the fetched row is empty and we don't want to preserve it.., + if (!$this->shouldPreserveEmptyRows && $this->isEmptyRow($this->currentlyProcessedRowData)) { + // ... skip it + return XMLProcessor::PROCESSING_CONTINUE; + } + + $this->numReadRows++; + + // If needed, we fill the empty cells + if ($this->numColumns === 0) { + $this->currentlyProcessedRowData = CellHelper::fillMissingArrayIndexes($this->currentlyProcessedRowData); + } + + // at this point, we have all the data we need for the row + // so that we can populate the buffer + return XMLProcessor::PROCESSING_STOP; + } + + /** + * @return int A return code that indicates what action should the processor take next + */ + protected function processWorksheetEndingNode() + { + // The closing "" marks the end of the file + $this->hasReachedEndOfFile = true; + + return XMLProcessor::PROCESSING_STOP; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" node + * @return int Row index + * @throws \Box\Spout\Common\Exception\InvalidArgumentException When the given cell index is invalid + */ + protected function getRowIndex($xmlReader) + { + // Get "r" attribute if present (from something like + $currentRowIndex = $xmlReader->getAttribute(self::XML_ATTRIBUTE_ROW_INDEX); + + return ($currentRowIndex !== null) ? + intval($currentRowIndex) : + $this->lastRowIndexProcessed + 1; + } + + /** + * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" node + * @return int Column index + * @throws \Box\Spout\Common\Exception\InvalidArgumentException When the given cell index is invalid + */ + protected function getColumnIndex($xmlReader) + { + // Get "r" attribute if present (from something like + $currentCellIndex = $xmlReader->getAttribute(self::XML_ATTRIBUTE_CELL_INDEX); + + return ($currentCellIndex !== null) ? + CellHelper::getColumnIndexFromCellIndex($currentCellIndex) : + $this->lastColumnIndexProcessed + 1; + } + + /** + * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node. + * + * @param \DOMNode $node + * @return string|int|float|bool|\DateTime|null The value associated with the cell (null when the cell has an error) + */ + protected function getCellValue($node) + { + return $this->cellValueFormatter->extractAndFormatNodeValue($node); + } + + /** + * @param array $rowData + * @return bool Whether the given row is empty + */ + protected function isEmptyRow($rowData) + { + return (count($rowData) === 1 && key($rowData) === ''); + } + + /** + * Return the current element, either an empty row or from the buffer. + * @link http://php.net/manual/en/iterator.current.php + * + * @return array|null + */ + public function current() + { + $rowDataForRowToBeProcessed = $this->rowDataBuffer; + + if ($this->shouldPreserveEmptyRows) { + // when we need to preserve empty rows, we will either return + // an empty row or the last row read. This depends whether the + // index of last row that was read matches the index of the last + // row whose value should be returned. + if ($this->lastRowIndexProcessed !== $this->nextRowIndexToBeProcessed) { + // return empty row if mismatch between last processed row + // and the row that needs to be returned + $rowDataForRowToBeProcessed = ['']; + } + } + + return $rowDataForRowToBeProcessed; + } + + /** + * Return the key of the current element. Here, the row index. + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + // TODO: This should return $this->nextRowIndexToBeProcessed + // but to avoid a breaking change, the return value for + // this function has been kept as the number of rows read. + return $this->shouldPreserveEmptyRows ? + $this->nextRowIndexToBeProcessed : + $this->numReadRows; + } + + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + $this->xmlReader->close(); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/Sheet.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Sheet.php new file mode 100644 index 0000000000..9baaef247f --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/Sheet.php @@ -0,0 +1,79 @@ +rowIterator = new RowIterator($filePath, $sheetDataXMLFilePath, $options, $sharedStringsHelper); + $this->index = $sheetIndex; + $this->name = $sheetName; + $this->isActive = $isSheetActive; + } + + /** + * @api + * @return \Box\Spout\Reader\XLSX\RowIterator + */ + public function getRowIterator() + { + return $this->rowIterator; + } + + /** + * @api + * @return int Index of the sheet, based on order in the workbook (zero-based) + */ + public function getIndex() + { + return $this->index; + } + + /** + * @api + * @return string Name of the sheet + */ + public function getName() + { + return $this->name; + } + + /** + * @api + * @return bool Whether the sheet was defined as active + */ + public function isActive() + { + return $this->isActive; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Reader/XLSX/SheetIterator.php b/lib/vendor/box/spout/src/Spout/Reader/XLSX/SheetIterator.php new file mode 100644 index 0000000000..7ba07d3428 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Reader/XLSX/SheetIterator.php @@ -0,0 +1,114 @@ +sheets = $sheetHelper->getSheets(); + + if (count($this->sheets) === 0) { + throw new NoSheetsFoundException('The file must contain at least one sheet.'); + } + } + + /** + * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * + * @return void + */ + public function rewind() + { + $this->currentSheetIndex = 0; + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * + * @return bool + */ + public function valid() + { + return ($this->currentSheetIndex < count($this->sheets)); + } + + /** + * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * + * @return void + */ + public function next() + { + // Using isset here because it is way faster than array_key_exists... + if (isset($this->sheets[$this->currentSheetIndex])) { + $currentSheet = $this->sheets[$this->currentSheetIndex]; + $currentSheet->getRowIterator()->end(); + + $this->currentSheetIndex++; + } + } + + /** + * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * + * @return \Box\Spout\Reader\XLSX\Sheet + */ + public function current() + { + return $this->sheets[$this->currentSheetIndex]; + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * + * @return int + */ + public function key() + { + return $this->currentSheetIndex + 1; + } + + /** + * Cleans up what was created to iterate over the object. + * + * @return void + */ + public function end() + { + // make sure we are not leaking memory in case the iteration stopped before the end + foreach ($this->sheets as $sheet) { + $sheet->getRowIterator()->end(); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/AbstractMultiSheetsWriter.php b/lib/vendor/box/spout/src/Spout/Writer/AbstractMultiSheetsWriter.php new file mode 100644 index 0000000000..d11966055a --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/AbstractMultiSheetsWriter.php @@ -0,0 +1,119 @@ +throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->shouldCreateNewSheetsAutomatically = $shouldCreateNewSheetsAutomatically; + return $this; + } + + /** + * Returns all the workbook's sheets + * + * @api + * @return Common\Sheet[] All the workbook's sheets + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function getSheets() + { + $this->throwIfBookIsNotAvailable(); + + $externalSheets = []; + $worksheets = $this->getWorkbook()->getWorksheets(); + + /** @var Common\Internal\WorksheetInterface $worksheet */ + foreach ($worksheets as $worksheet) { + $externalSheets[] = $worksheet->getExternalSheet(); + } + + return $externalSheets; + } + + /** + * Creates a new sheet and make it the current sheet. The data will now be written to this sheet. + * + * @api + * @return Common\Sheet The created sheet + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function addNewSheetAndMakeItCurrent() + { + $this->throwIfBookIsNotAvailable(); + $worksheet = $this->getWorkbook()->addNewSheetAndMakeItCurrent(); + + return $worksheet->getExternalSheet(); + } + + /** + * Returns the current sheet + * + * @api + * @return Common\Sheet The current sheet + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + */ + public function getCurrentSheet() + { + $this->throwIfBookIsNotAvailable(); + return $this->getWorkbook()->getCurrentWorksheet()->getExternalSheet(); + } + + /** + * Sets the given sheet as the current one. New data will be written to this sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @api + * @param Common\Sheet $sheet The sheet to set as current + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the writer has not been opened yet + * @throws \Box\Spout\Writer\Exception\SheetNotFoundException If the given sheet does not exist in the workbook + */ + public function setCurrentSheet($sheet) + { + $this->throwIfBookIsNotAvailable(); + $this->getWorkbook()->setCurrentSheet($sheet); + } + + /** + * Checks if the book has been created. Throws an exception if not created yet. + * + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet + */ + protected function throwIfBookIsNotAvailable() + { + if (!$this->getWorkbook()) { + throw new WriterNotOpenedException('The writer must be opened before performing this action.'); + } + } +} + diff --git a/lib/vendor/box/spout/src/Spout/Writer/AbstractWriter.php b/lib/vendor/box/spout/src/Spout/Writer/AbstractWriter.php new file mode 100644 index 0000000000..83e190f5f3 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/AbstractWriter.php @@ -0,0 +1,384 @@ +defaultRowStyle = $this->getDefaultRowStyle(); + $this->resetRowStyleToDefault(); + } + + /** + * Sets the default styles for all rows added with "addRow". + * Overriding the default style instead of using "addRowWithStyle" improves performance by 20%. + * @see https://github.com/box/spout/issues/272 + * + * @param Style\Style $defaultStyle + * @return AbstractWriter + */ + public function setDefaultRowStyle($defaultStyle) + { + $this->defaultRowStyle = $defaultStyle; + $this->resetRowStyleToDefault(); + return $this; + } + + /** + * @param \Box\Spout\Common\Helper\GlobalFunctionsHelper $globalFunctionsHelper + * @return AbstractWriter + */ + public function setGlobalFunctionsHelper($globalFunctionsHelper) + { + $this->globalFunctionsHelper = $globalFunctionsHelper; + return $this; + } + + /** + * Inits the writer and opens it to accept data. + * By using this method, the data will be written to a file. + * + * @api + * @param string $outputFilePath Path of the output file that will contain the data + * @return AbstractWriter + * @throws \Box\Spout\Common\Exception\IOException If the writer cannot be opened or if the given path is not writable + */ + public function openToFile($outputFilePath) + { + $this->outputFilePath = $outputFilePath; + + $this->filePointer = $this->globalFunctionsHelper->fopen($this->outputFilePath, 'wb+'); + $this->throwIfFilePointerIsNotAvailable(); + + $this->openWriter(); + $this->isWriterOpened = true; + + return $this; + } + + /** + * Inits the writer and opens it to accept data. + * By using this method, the data will be outputted directly to the browser. + * + * @codeCoverageIgnore + * + * @api + * @param string $outputFileName Name of the output file that will contain the data. If a path is passed in, only the file name will be kept + * @return AbstractWriter + * @throws \Box\Spout\Common\Exception\IOException If the writer cannot be opened + */ + public function openToBrowser($outputFileName) + { + $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName); + + $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w'); + $this->throwIfFilePointerIsNotAvailable(); + + // Clear any previous output (otherwise the generated file will be corrupted) + // @see https://github.com/box/spout/issues/241 + $this->globalFunctionsHelper->ob_end_clean(); + + // Set headers + $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType); + $this->globalFunctionsHelper->header('Content-Disposition: attachment; filename="' . $this->outputFilePath . '"'); + + /* + * When forcing the download of a file over SSL,IE8 and lower browsers fail + * if the Cache-Control and Pragma headers are not set. + * + * @see http://support.microsoft.com/KB/323308 + * @see https://github.com/liuggio/ExcelBundle/issues/45 + */ + $this->globalFunctionsHelper->header('Cache-Control: max-age=0'); + $this->globalFunctionsHelper->header('Pragma: public'); + + $this->openWriter(); + $this->isWriterOpened = true; + + return $this; + } + + /** + * Checks if the pointer to the file/stream to write to is available. + * Will throw an exception if not available. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the pointer is not available + */ + protected function throwIfFilePointerIsNotAvailable() + { + if (!$this->filePointer) { + throw new IOException('File pointer has not be opened'); + } + } + + /** + * Checks if the writer has already been opened, since some actions must be done before it gets opened. + * Throws an exception if already opened. + * + * @param string $message Error message + * @return void + * @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened and must not be. + */ + protected function throwIfWriterAlreadyOpened($message) + { + if ($this->isWriterOpened) { + throw new WriterAlreadyOpenedException($message); + } + } + + /** + * Write given data to the output. New data will be appended to end of stream. + * + * @param array $dataRow Array containing data to be streamed. + * If empty, no data is added (i.e. not even as a blank row) + * Example: $dataRow = ['data1', 1234, null, '', 'data5', false]; + * @api + * @return AbstractWriter + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + * @throws \Box\Spout\Common\Exception\SpoutException If anything else goes wrong while writing data + */ + public function addRow(array $dataRow) + { + if ($this->isWriterOpened) { + // empty $dataRow should not add an empty line + if (!empty($dataRow)) { + try { + $this->addRowToWriter($dataRow, $this->rowStyle); + } catch (SpoutException $e) { + // if an exception occurs while writing data, + // close the writer and remove all files created so far. + $this->closeAndAttemptToCleanupAllFiles(); + + // re-throw the exception to alert developers of the error + throw $e; + } + } + } else { + throw new WriterNotOpenedException('The writer needs to be opened before adding row.'); + } + + return $this; + } + + /** + * Write given data to the output and apply the given style. + * @see addRow + * + * @api + * @param array $dataRow Array of array containing data to be streamed. + * @param Style\Style $style Style to be applied to the row. + * @return AbstractWriter + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + public function addRowWithStyle(array $dataRow, $style) + { + if (!$style instanceof Style\Style) { + throw new InvalidArgumentException('The "$style" argument must be a Style instance and cannot be NULL.'); + } + + $this->setRowStyle($style); + $this->addRow($dataRow); + $this->resetRowStyleToDefault(); + + return $this; + } + + /** + * Write given data to the output. New data will be appended to end of stream. + * + * @api + * @param array $dataRows Array of array containing data to be streamed. + * If a row is empty, it won't be added (i.e. not even as a blank row) + * Example: $dataRows = [ + * ['data11', 12, , '', 'data13'], + * ['data21', 'data22', null, false], + * ]; + * @return AbstractWriter + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + public function addRows(array $dataRows) + { + if (!empty($dataRows)) { + $firstRow = reset($dataRows); + if (!is_array($firstRow)) { + throw new InvalidArgumentException('The input should be an array of arrays'); + } + + foreach ($dataRows as $dataRow) { + $this->addRow($dataRow); + } + } + + return $this; + } + + /** + * Write given data to the output and apply the given style. + * @see addRows + * + * @api + * @param array $dataRows Array of array containing data to be streamed. + * @param Style\Style $style Style to be applied to the rows. + * @return AbstractWriter + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If the input param is not valid + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If this function is called before opening the writer + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + public function addRowsWithStyle(array $dataRows, $style) + { + if (!$style instanceof Style\Style) { + throw new InvalidArgumentException('The "$style" argument must be a Style instance and cannot be NULL.'); + } + + $this->setRowStyle($style); + $this->addRows($dataRows); + $this->resetRowStyleToDefault(); + + return $this; + } + + /** + * Returns the default style to be applied to rows. + * Can be overriden by children to have a custom style. + * + * @return Style\Style + */ + protected function getDefaultRowStyle() + { + return (new StyleBuilder())->build(); + } + + /** + * Sets the style to be applied to the next written rows + * until it is changed or reset. + * + * @param Style\Style $style + * @return void + */ + private function setRowStyle($style) + { + // Merge given style with the default one to inherit custom properties + $this->rowStyle = $style->mergeWith($this->defaultRowStyle); + } + + /** + * Resets the style to be applied to the next written rows. + * + * @return void + */ + private function resetRowStyleToDefault() + { + $this->rowStyle = $this->defaultRowStyle; + } + + /** + * Closes the writer. This will close the streamer as well, preventing new data + * to be written to the file. + * + * @api + * @return void + */ + public function close() + { + if (!$this->isWriterOpened) { + return; + } + + $this->closeWriter(); + + if (is_resource($this->filePointer)) { + $this->globalFunctionsHelper->fclose($this->filePointer); + } + + $this->isWriterOpened = false; + } + + /** + * Closes the writer and attempts to cleanup all files that were + * created during the writing process (temp files & final file). + * + * @return void + */ + private function closeAndAttemptToCleanupAllFiles() + { + // close the writer, which should remove all temp files + $this->close(); + + // remove output file if it was created + if ($this->globalFunctionsHelper->file_exists($this->outputFilePath)) { + $outputFolderPath = dirname($this->outputFilePath); + $fileSystemHelper = new FileSystemHelper($outputFolderPath); + $fileSystemHelper->deleteFile($this->outputFilePath); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/CSV/Writer.php b/lib/vendor/box/spout/src/Spout/Writer/CSV/Writer.php new file mode 100644 index 0000000000..f7f1fda541 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/CSV/Writer.php @@ -0,0 +1,118 @@ +fieldDelimiter = $fieldDelimiter; + return $this; + } + + /** + * Sets the field enclosure for the CSV + * + * @api + * @param string $fieldEnclosure Character that enclose fields + * @return Writer + */ + public function setFieldEnclosure($fieldEnclosure) + { + $this->fieldEnclosure = $fieldEnclosure; + return $this; + } + + /** + * Set if a BOM has to be added to the file + * + * @param bool $shouldAddBOM + * @return Writer + */ + public function setShouldAddBOM($shouldAddBOM) + { + $this->shouldAddBOM = (bool) $shouldAddBOM; + return $this; + } + + /** + * Opens the CSV streamer and makes it ready to accept data. + * + * @return void + */ + protected function openWriter() + { + if ($this->shouldAddBOM) { + // Adds UTF-8 BOM for Unicode compatibility + $this->globalFunctionsHelper->fputs($this->filePointer, EncodingHelper::BOM_UTF8); + } + } + + /** + * Adds data to the currently opened writer. + * + * @param array $dataRow Array containing data to be written. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Ignored here since CSV does not support styling. + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + protected function addRowToWriter(array $dataRow, $style) + { + $wasWriteSuccessful = $this->globalFunctionsHelper->fputcsv($this->filePointer, $dataRow, $this->fieldDelimiter, $this->fieldEnclosure); + if ($wasWriteSuccessful === false) { + throw new IOException('Unable to write data'); + } + + $this->lastWrittenRowIndex++; + if ($this->lastWrittenRowIndex % self::FLUSH_THRESHOLD === 0) { + $this->globalFunctionsHelper->fflush($this->filePointer); + } + } + + /** + * Closes the CSV streamer, preventing any additional writing. + * If set, sets the headers and redirects output to the browser. + * + * @return void + */ + protected function closeWriter() + { + $this->lastWrittenRowIndex = 0; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/AbstractStyleHelper.php b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/AbstractStyleHelper.php new file mode 100644 index 0000000000..fa5e26745e --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/AbstractStyleHelper.php @@ -0,0 +1,138 @@ + [STYLE_ID] mapping table, keeping track of the registered styles */ + protected $serializedStyleToStyleIdMappingTable = []; + + /** @var array [STYLE_ID] => [STYLE] mapping table, keeping track of the registered styles */ + protected $styleIdToStyleMappingTable = []; + + /** + * @param \Box\Spout\Writer\Style\Style $defaultStyle + */ + public function __construct($defaultStyle) + { + // This ensures that the default style is the first one to be registered + $this->registerStyle($defaultStyle); + } + + /** + * Registers the given style as a used style. + * Duplicate styles won't be registered more than once. + * + * @param \Box\Spout\Writer\Style\Style $style The style to be registered + * @return \Box\Spout\Writer\Style\Style The registered style, updated with an internal ID. + */ + public function registerStyle($style) + { + $serializedStyle = $style->serialize(); + + if (!$this->hasStyleAlreadyBeenRegistered($style)) { + $nextStyleId = count($this->serializedStyleToStyleIdMappingTable); + $style->setId($nextStyleId); + + $this->serializedStyleToStyleIdMappingTable[$serializedStyle] = $nextStyleId; + $this->styleIdToStyleMappingTable[$nextStyleId] = $style; + } + + return $this->getStyleFromSerializedStyle($serializedStyle); + } + + /** + * Returns whether the given style has already been registered. + * + * @param \Box\Spout\Writer\Style\Style $style + * @return bool + */ + protected function hasStyleAlreadyBeenRegistered($style) + { + $serializedStyle = $style->serialize(); + + // Using isset here because it is way faster than array_key_exists... + return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]); + } + + /** + * Returns the registered style associated to the given serialization. + * + * @param string $serializedStyle The serialized style from which the actual style should be fetched from + * @return \Box\Spout\Writer\Style\Style + */ + protected function getStyleFromSerializedStyle($serializedStyle) + { + $styleId = $this->serializedStyleToStyleIdMappingTable[$serializedStyle]; + return $this->styleIdToStyleMappingTable[$styleId]; + } + + /** + * @return \Box\Spout\Writer\Style\Style[] List of registered styles + */ + protected function getRegisteredStyles() + { + return array_values($this->styleIdToStyleMappingTable); + } + + /** + * Returns the default style + * + * @return \Box\Spout\Writer\Style\Style Default style + */ + protected function getDefaultStyle() + { + // By construction, the default style has ID 0 + return $this->styleIdToStyleMappingTable[0]; + } + + /** + * Apply additional styles if the given row needs it. + * Typically, set "wrap text" if a cell contains a new line. + * + * @param \Box\Spout\Writer\Style\Style $style The original style + * @param array $dataRow The row the style will be applied to + * @return \Box\Spout\Writer\Style\Style The updated style + */ + public function applyExtraStylesIfNeeded($style, $dataRow) + { + $updatedStyle = $this->applyWrapTextIfCellContainsNewLine($style, $dataRow); + return $updatedStyle; + } + + /** + * Set the "wrap text" option if a cell of the given row contains a new line. + * + * @NOTE: There is a bug on the Mac version of Excel (2011 and below) where new lines + * are ignored even when the "wrap text" option is set. This only occurs with + * inline strings (shared strings do work fine). + * A workaround would be to encode "\n" as "_x000D_" but it does not work + * on the Windows version of Excel... + * + * @param \Box\Spout\Writer\Style\Style $style The original style + * @param array $dataRow The row the style will be applied to + * @return \Box\Spout\Writer\Style\Style The eventually updated style + */ + protected function applyWrapTextIfCellContainsNewLine($style, $dataRow) + { + // if the "wrap text" option is already set, no-op + if ($style->hasSetWrapText()) { + return $style; + } + + foreach ($dataRow as $cell) { + if (is_string($cell) && strpos($cell, "\n") !== false) { + $style->setShouldWrapText(); + break; + } + } + + return $style; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/CellHelper.php b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/CellHelper.php new file mode 100644 index 0000000000..50ead93be4 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/CellHelper.php @@ -0,0 +1,91 @@ + cell index */ + private static $columnIndexToCellIndexCache = []; + + /** + * Returns the cell index (base 26) associated to the base 10 column index. + * Excel uses A to Z letters for column indexing, where A is the 1st column, + * Z is the 26th and AA is the 27th. + * The mapping is zero based, so that 0 maps to A, B maps to 1, Z to 25 and AA to 26. + * + * @param int $columnIndex The Excel column index (0, 42, ...) + * @return string The associated cell index ('A', 'BC', ...) + */ + public static function getCellIndexFromColumnIndex($columnIndex) + { + $originalColumnIndex = $columnIndex; + + // Using isset here because it is way faster than array_key_exists... + if (!isset(self::$columnIndexToCellIndexCache[$originalColumnIndex])) { + $cellIndex = ''; + $capitalAAsciiValue = ord('A'); + + do { + $modulus = $columnIndex % 26; + $cellIndex = chr($capitalAAsciiValue + $modulus) . $cellIndex; + + // substracting 1 because it's zero-based + $columnIndex = intval($columnIndex / 26) - 1; + + } while ($columnIndex >= 0); + + self::$columnIndexToCellIndexCache[$originalColumnIndex] = $cellIndex; + } + + return self::$columnIndexToCellIndexCache[$originalColumnIndex]; + } + + /** + * @param $value + * @return bool Whether the given value is considered "empty" + */ + public static function isEmpty($value) + { + return ($value === null || $value === ''); + } + + /** + * @param $value + * @return bool Whether the given value is a non empty string + */ + public static function isNonEmptyString($value) + { + return (gettype($value) === 'string' && $value !== ''); + } + + /** + * Returns whether the given value is numeric. + * A numeric value is from type "integer" or "double" ("float" is not returned by gettype). + * + * @param $value + * @return bool Whether the given value is numeric + */ + public static function isNumeric($value) + { + $valueType = gettype($value); + return ($valueType === 'integer' || $valueType === 'double'); + } + + /** + * Returns whether the given value is boolean. + * "true"/"false" and 0/1 are not booleans. + * + * @param $value + * @return bool Whether the given value is boolean + */ + public static function isBoolean($value) + { + return gettype($value) === 'boolean'; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/ZipHelper.php b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/ZipHelper.php new file mode 100644 index 0000000000..1670d179bf --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Common/Helper/ZipHelper.php @@ -0,0 +1,217 @@ +tmpFolderPath = $tmpFolderPath; + } + + /** + * Returns the already created ZipArchive instance or + * creates one if none exists. + * + * @return \ZipArchive + */ + protected function createOrGetZip() + { + if (!isset($this->zip)) { + $this->zip = new \ZipArchive(); + $zipFilePath = $this->getZipFilePath(); + + $this->zip->open($zipFilePath, \ZipArchive::CREATE|\ZipArchive::OVERWRITE); + } + + return $this->zip; + } + + /** + * @return string Path where the zip file of the given folder will be created + */ + public function getZipFilePath() + { + return $this->tmpFolderPath . self::ZIP_EXTENSION; + } + + /** + * Adds the given file, located under the given root folder to the archive. + * The file will be compressed. + * + * Example of use: + * addFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml'); + * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml' + * + * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree. + * @param string $localFilePath Path of the file to be added, under the root folder + * @param string|void $existingFileMode Controls what to do when trying to add an existing file + * @return void + */ + public function addFileToArchive($rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE) + { + $this->addFileToArchiveWithCompressionMethod( + $rootFolderPath, + $localFilePath, + $existingFileMode, + \ZipArchive::CM_DEFAULT + ); + } + + /** + * Adds the given file, located under the given root folder to the archive. + * The file will NOT be compressed. + * + * Example of use: + * addUncompressedFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml'); + * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml' + * + * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree. + * @param string $localFilePath Path of the file to be added, under the root folder + * @param string|void $existingFileMode Controls what to do when trying to add an existing file + * @return void + */ + public function addUncompressedFileToArchive($rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE) + { + $this->addFileToArchiveWithCompressionMethod( + $rootFolderPath, + $localFilePath, + $existingFileMode, + \ZipArchive::CM_STORE + ); + } + + /** + * Adds the given file, located under the given root folder to the archive. + * The file will NOT be compressed. + * + * Example of use: + * addUncompressedFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml'); + * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml' + * + * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree. + * @param string $localFilePath Path of the file to be added, under the root folder + * @param string $existingFileMode Controls what to do when trying to add an existing file + * @param int $compressionMethod The compression method + * @return void + */ + protected function addFileToArchiveWithCompressionMethod($rootFolderPath, $localFilePath, $existingFileMode, $compressionMethod) + { + $zip = $this->createOrGetZip(); + + if (!$this->shouldSkipFile($zip, $localFilePath, $existingFileMode)) { + $normalizedFullFilePath = $this->getNormalizedRealPath($rootFolderPath . '/' . $localFilePath); + $zip->addFile($normalizedFullFilePath, $localFilePath); + + if (self::canChooseCompressionMethod()) { + $zip->setCompressionName($localFilePath, $compressionMethod); + } + } + } + + /** + * @return bool Whether it is possible to choose the desired compression method to be used + */ + public static function canChooseCompressionMethod() + { + // setCompressionName() is a PHP7+ method... + return (method_exists(new \ZipArchive(), 'setCompressionName')); + } + + /** + * @param string $folderPath Path to the folder to be zipped + * @param string|void $existingFileMode Controls what to do when trying to add an existing file + * @return void + */ + public function addFolderToArchive($folderPath, $existingFileMode = self::EXISTING_FILES_OVERWRITE) + { + $zip = $this->createOrGetZip(); + + $folderRealPath = $this->getNormalizedRealPath($folderPath) . '/'; + $itemIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST); + + foreach ($itemIterator as $itemInfo) { + $itemRealPath = $this->getNormalizedRealPath($itemInfo->getPathname()); + $itemLocalPath = str_replace($folderRealPath, '', $itemRealPath); + + if ($itemInfo->isFile() && !$this->shouldSkipFile($zip, $itemLocalPath, $existingFileMode)) { + $zip->addFile($itemRealPath, $itemLocalPath); + } + } + } + + /** + * @param \ZipArchive $zip + * @param string $itemLocalPath + * @param string $existingFileMode + * @return bool Whether the file should be added to the archive or skipped + */ + protected function shouldSkipFile($zip, $itemLocalPath, $existingFileMode) + { + // Skip files if: + // - EXISTING_FILES_SKIP mode chosen + // - File already exists in the archive + return ($existingFileMode === self::EXISTING_FILES_SKIP && $zip->locateName($itemLocalPath) !== false); + } + + /** + * Returns canonicalized absolute pathname, containing only forward slashes. + * + * @param string $path Path to normalize + * @return string Normalized and canonicalized path + */ + protected function getNormalizedRealPath($path) + { + $realPath = realpath($path); + return str_replace(DIRECTORY_SEPARATOR, '/', $realPath); + } + + /** + * Closes the archive and copies it into the given stream + * + * @param resource $streamPointer Pointer to the stream to copy the zip + * @return void + */ + public function closeArchiveAndCopyToStream($streamPointer) + { + $zip = $this->createOrGetZip(); + $zip->close(); + unset($this->zip); + + $this->copyZipToStream($streamPointer); + } + + /** + * Streams the contents of the zip file into the given stream + * + * @param resource $pointer Pointer to the stream to copy the zip + * @return void + */ + protected function copyZipToStream($pointer) + { + $zipFilePointer = fopen($this->getZipFilePath(), 'r'); + stream_copy_to_stream($zipFilePointer, $pointer); + fclose($zipFilePointer); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/AbstractWorkbook.php b/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/AbstractWorkbook.php new file mode 100644 index 0000000000..e852e1a84d --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/AbstractWorkbook.php @@ -0,0 +1,192 @@ +shouldCreateNewSheetsAutomatically = $shouldCreateNewSheetsAutomatically; + $this->internalId = uniqid(); + } + + /** + * @return \Box\Spout\Writer\Common\Helper\AbstractStyleHelper The specific style helper + */ + abstract protected function getStyleHelper(); + + /** + * @return int Maximum number of rows/columns a sheet can contain + */ + abstract protected function getMaxRowsPerWorksheet(); + + /** + * Creates a new sheet in the workbook. The current sheet remains unchanged. + * + * @return WorksheetInterface The created sheet + * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing + */ + abstract public function addNewSheet(); + + /** + * Creates a new sheet in the workbook and make it the current sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @return WorksheetInterface The created sheet + * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing + */ + public function addNewSheetAndMakeItCurrent() + { + $worksheet = $this->addNewSheet(); + $this->setCurrentWorksheet($worksheet); + + return $worksheet; + } + + /** + * @return WorksheetInterface[] All the workbook's sheets + */ + public function getWorksheets() + { + return $this->worksheets; + } + + /** + * Returns the current sheet + * + * @return WorksheetInterface The current sheet + */ + public function getCurrentWorksheet() + { + return $this->currentWorksheet; + } + + /** + * Sets the given sheet as the current one. New data will be written to this sheet. + * The writing will resume where it stopped (i.e. data won't be truncated). + * + * @param \Box\Spout\Writer\Common\Sheet $sheet The "external" sheet to set as current + * @return void + * @throws \Box\Spout\Writer\Exception\SheetNotFoundException If the given sheet does not exist in the workbook + */ + public function setCurrentSheet($sheet) + { + $worksheet = $this->getWorksheetFromExternalSheet($sheet); + if ($worksheet !== null) { + $this->currentWorksheet = $worksheet; + } else { + throw new SheetNotFoundException('The given sheet does not exist in the workbook.'); + } + } + + /** + * @param WorksheetInterface $worksheet + * @return void + */ + protected function setCurrentWorksheet($worksheet) + { + $this->currentWorksheet = $worksheet; + } + + /** + * Returns the worksheet associated to the given external sheet. + * + * @param \Box\Spout\Writer\Common\Sheet $sheet + * @return WorksheetInterface|null The worksheet associated to the given external sheet or null if not found. + */ + protected function getWorksheetFromExternalSheet($sheet) + { + $worksheetFound = null; + + foreach ($this->worksheets as $worksheet) { + if ($worksheet->getExternalSheet() === $sheet) { + $worksheetFound = $worksheet; + break; + } + } + + return $worksheetFound; + } + + /** + * Adds data to the current sheet. + * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination + * with the creation of new worksheets if one worksheet has reached its maximum capicity. + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. + * @return void + * @throws \Box\Spout\Common\Exception\IOException If trying to create a new sheet and unable to open the sheet for writing + * @throws \Box\Spout\Writer\Exception\WriterException If unable to write data + */ + public function addRowToCurrentWorksheet($dataRow, $style) + { + $currentWorksheet = $this->getCurrentWorksheet(); + $hasReachedMaxRows = $this->hasCurrentWorkseetReachedMaxRows(); + $styleHelper = $this->getStyleHelper(); + + // if we reached the maximum number of rows for the current sheet... + if ($hasReachedMaxRows) { + // ... continue writing in a new sheet if option set + if ($this->shouldCreateNewSheetsAutomatically) { + $currentWorksheet = $this->addNewSheetAndMakeItCurrent(); + + $updatedStyle = $styleHelper->applyExtraStylesIfNeeded($style, $dataRow); + $registeredStyle = $styleHelper->registerStyle($updatedStyle); + $currentWorksheet->addRow($dataRow, $registeredStyle); + } else { + // otherwise, do nothing as the data won't be read anyways + } + } else { + $updatedStyle = $styleHelper->applyExtraStylesIfNeeded($style, $dataRow); + $registeredStyle = $styleHelper->registerStyle($updatedStyle); + $currentWorksheet->addRow($dataRow, $registeredStyle); + } + } + + /** + * @return bool Whether the current worksheet has reached the maximum number of rows per sheet. + */ + protected function hasCurrentWorkseetReachedMaxRows() + { + $currentWorksheet = $this->getCurrentWorksheet(); + return ($currentWorksheet->getLastWrittenRowIndex() >= $this->getMaxRowsPerWorksheet()); + } + + /** + * Closes the workbook and all its associated sheets. + * All the necessary files are written to disk and zipped together to create the ODS file. + * All the temporary files are then deleted. + * + * @param resource $finalFilePointer Pointer to the ODS that will be created + * @return void + */ + abstract public function close($finalFilePointer); +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/WorkbookInterface.php b/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/WorkbookInterface.php new file mode 100644 index 0000000000..fda0793486 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Common/Internal/WorkbookInterface.php @@ -0,0 +1,74 @@ + [[SHEET_INDEX] => [SHEET_NAME]] keeping track of sheets' name to enforce uniqueness per workbook */ + protected static $SHEETS_NAME_USED = []; + + /** @var int Index of the sheet, based on order in the workbook (zero-based) */ + protected $index; + + /** @var string ID of the sheet's associated workbook. Used to restrict sheet name uniqueness enforcement to a single workbook */ + protected $associatedWorkbookId; + + /** @var string Name of the sheet */ + protected $name; + + /** @var \Box\Spout\Common\Helper\StringHelper */ + protected $stringHelper; + + /** + * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based) + * @param string $associatedWorkbookId ID of the sheet's associated workbook + */ + public function __construct($sheetIndex, $associatedWorkbookId) + { + $this->index = $sheetIndex; + $this->associatedWorkbookId = $associatedWorkbookId; + if (!isset(self::$SHEETS_NAME_USED[$associatedWorkbookId])) { + self::$SHEETS_NAME_USED[$associatedWorkbookId] = []; + } + + $this->stringHelper = new StringHelper(); + $this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1)); + } + + /** + * @api + * @return int Index of the sheet, based on order in the workbook (zero-based) + */ + public function getIndex() + { + return $this->index; + } + + /** + * @api + * @return string Name of the sheet + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the name of the sheet. Note that Excel has some restrictions on the name: + * - it should not be blank + * - it should not exceed 31 characters + * - it should not contain these characters: \ / ? * : [ or ] + * - it should be unique + * + * @api + * @param string $name Name of the sheet + * @return Sheet + * @throws \Box\Spout\Writer\Exception\InvalidSheetNameException If the sheet's name is invalid. + */ + public function setName($name) + { + $this->throwIfNameIsInvalid($name); + + $this->name = $name; + self::$SHEETS_NAME_USED[$this->associatedWorkbookId][$this->index] = $name; + + return $this; + } + + /** + * Throws an exception if the given sheet's name is not valid. + * @see Sheet::setName for validity rules. + * + * @param string $name + * @return void + * @throws \Box\Spout\Writer\Exception\InvalidSheetNameException If the sheet's name is invalid. + */ + protected function throwIfNameIsInvalid($name) + { + if (!is_string($name)) { + $actualType = gettype($name); + $errorMessage = "The sheet's name is invalid. It must be a string ($actualType given)."; + throw new InvalidSheetNameException($errorMessage); + } + + $failedRequirements = []; + $nameLength = $this->stringHelper->getStringLength($name); + + if (!$this->isNameUnique($name)) { + $failedRequirements[] = 'It should be unique'; + } else { + if ($nameLength === 0) { + $failedRequirements[] = 'It should not be blank'; + } else { + if ($nameLength > self::MAX_LENGTH_SHEET_NAME) { + $failedRequirements[] = 'It should not exceed 31 characters'; + } + + if ($this->doesContainInvalidCharacters($name)) { + $failedRequirements[] = 'It should not contain these characters: \\ / ? * : [ or ]'; + } + + if ($this->doesStartOrEndWithSingleQuote($name)) { + $failedRequirements[] = 'It should not start or end with a single quote'; + } + } + } + + if (count($failedRequirements) !== 0) { + $errorMessage = "The sheet's name (\"$name\") is invalid. It did not respect these rules:\n - "; + $errorMessage .= implode("\n - ", $failedRequirements); + throw new InvalidSheetNameException($errorMessage); + } + } + + /** + * Returns whether the given name contains at least one invalid character. + * @see Sheet::$INVALID_CHARACTERS_IN_SHEET_NAME for the full list. + * + * @param string $name + * @return bool TRUE if the name contains invalid characters, FALSE otherwise. + */ + protected function doesContainInvalidCharacters($name) + { + return (str_replace(self::$INVALID_CHARACTERS_IN_SHEET_NAME, '', $name) !== $name); + } + + /** + * Returns whether the given name starts or ends with a single quote + * + * @param string $name + * @return bool TRUE if the name starts or ends with a single quote, FALSE otherwise. + */ + protected function doesStartOrEndWithSingleQuote($name) + { + $startsWithSingleQuote = ($this->stringHelper->getCharFirstOccurrencePosition('\'', $name) === 0); + $endsWithSingleQuote = ($this->stringHelper->getCharLastOccurrencePosition('\'', $name) === ($this->stringHelper->getStringLength($name) - 1)); + + return ($startsWithSingleQuote || $endsWithSingleQuote); + } + + /** + * Returns whether the given name is unique. + * + * @param string $name + * @return bool TRUE if the name is unique, FALSE otherwise. + */ + protected function isNameUnique($name) + { + foreach (self::$SHEETS_NAME_USED[$this->associatedWorkbookId] as $sheetIndex => $sheetName) { + if ($sheetIndex !== $this->index && $sheetName === $name) { + return false; + } + } + + return true; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Exception/Border/InvalidNameException.php b/lib/vendor/box/spout/src/Spout/Writer/Exception/Border/InvalidNameException.php new file mode 100644 index 0000000000..13ac06c2dc --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Exception/Border/InvalidNameException.php @@ -0,0 +1,16 @@ + + */ +class BorderHelper +{ + /** + * Width mappings + * + * @var array + */ + protected static $widthMap = [ + Border::WIDTH_THIN => '0.75pt', + Border::WIDTH_MEDIUM => '1.75pt', + Border::WIDTH_THICK => '2.5pt', + ]; + + /** + * Style mapping + * + * @var array + */ + protected static $styleMap = [ + Border::STYLE_SOLID => 'solid', + Border::STYLE_DASHED => 'dashed', + Border::STYLE_DOTTED => 'dotted', + Border::STYLE_DOUBLE => 'double', + ]; + + /** + * @param BorderPart $borderPart + * @return string + */ + public static function serializeBorderPart(BorderPart $borderPart) + { + $definition = 'fo:border-%s="%s"'; + + if ($borderPart->getStyle() === Border::STYLE_NONE) { + $borderPartDefinition = sprintf($definition, $borderPart->getName(), 'none'); + } else { + $attributes = [ + self::$widthMap[$borderPart->getWidth()], + self::$styleMap[$borderPart->getStyle()], + '#' . $borderPart->getColor(), + ]; + $borderPartDefinition = sprintf($definition, $borderPart->getName(), implode(' ', $attributes)); + } + + return $borderPartDefinition; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/FileSystemHelper.php b/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/FileSystemHelper.php new file mode 100644 index 0000000000..34ace0ad13 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/FileSystemHelper.php @@ -0,0 +1,279 @@ +rootFolder; + } + + /** + * @return string + */ + public function getSheetsContentTempFolder() + { + return $this->sheetsContentTempFolder; + } + + /** + * Creates all the folders needed to create a ODS file, as well as the files that won't change. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to create at least one of the base folders + */ + public function createBaseFilesAndFolders() + { + $this + ->createRootFolder() + ->createMetaInfoFolderAndFile() + ->createSheetsContentTempFolder() + ->createMetaFile() + ->createMimetypeFile(); + } + + /** + * Creates the folder that will be used as root + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder + */ + protected function createRootFolder() + { + $this->rootFolder = $this->createFolder($this->baseFolderRealPath, uniqid('ods')); + return $this; + } + + /** + * Creates the "META-INF" folder under the root folder as well as the "manifest.xml" file in it + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or the "manifest.xml" file + */ + protected function createMetaInfoFolderAndFile() + { + $this->metaInfFolder = $this->createFolder($this->rootFolder, self::META_INF_FOLDER_NAME); + + $this->createManifestFile(); + + return $this; + } + + /** + * Creates the "manifest.xml" file under the "META-INF" folder (under root) + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createManifestFile() + { + $manifestXmlFileContents = << + + + + + + +EOD; + + $this->createFileWithContents($this->metaInfFolder, self::MANIFEST_XML_FILE_NAME, $manifestXmlFileContents); + + return $this; + } + + /** + * Creates the temp folder where specific sheets content will be written to. + * This folder is not part of the final ODS file and is only used to be able to jump between sheets. + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder + */ + protected function createSheetsContentTempFolder() + { + $this->sheetsContentTempFolder = $this->createFolder($this->rootFolder, self::SHEETS_CONTENT_TEMP_FOLDER_NAME); + return $this; + } + + /** + * Creates the "meta.xml" file under the root folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createMetaFile() + { + $appName = self::APP_NAME; + $createdDate = (new \DateTime())->format(\DateTime::W3C); + + $metaXmlFileContents = << + + + $appName + $createdDate + $createdDate + + +EOD; + + $this->createFileWithContents($this->rootFolder, self::META_XML_FILE_NAME, $metaXmlFileContents); + + return $this; + } + + /** + * Creates the "mimetype" file under the root folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createMimetypeFile() + { + $this->createFileWithContents($this->rootFolder, self::MIMETYPE_FILE_NAME, self::MIMETYPE); + return $this; + } + + /** + * Creates the "content.xml" file under the root folder + * + * @param Worksheet[] $worksheets + * @param StyleHelper $styleHelper + * @return FileSystemHelper + */ + public function createContentFile($worksheets, $styleHelper) + { + $contentXmlFileContents = << + +EOD; + + $contentXmlFileContents .= $styleHelper->getContentXmlFontFaceSectionContent(); + $contentXmlFileContents .= $styleHelper->getContentXmlAutomaticStylesSectionContent(count($worksheets)); + + $contentXmlFileContents .= ''; + + $this->createFileWithContents($this->rootFolder, self::CONTENT_XML_FILE_NAME, $contentXmlFileContents); + + // Append sheets content to "content.xml" + $contentXmlFilePath = $this->rootFolder . '/' . self::CONTENT_XML_FILE_NAME; + $contentXmlHandle = fopen($contentXmlFilePath, 'a'); + + foreach ($worksheets as $worksheet) { + // write the "" node, with the final sheet's name + fwrite($contentXmlHandle, $worksheet->getTableElementStartAsString()); + + $worksheetFilePath = $worksheet->getWorksheetFilePath(); + $this->copyFileContentsToTarget($worksheetFilePath, $contentXmlHandle); + + fwrite($contentXmlHandle, ''); + } + + $contentXmlFileContents = ''; + + fwrite($contentXmlHandle, $contentXmlFileContents); + fclose($contentXmlHandle); + + return $this; + } + + /** + * Streams the content of the file at the given path into the target resource. + * Depending on which mode the target resource was created with, it will truncate then copy + * or append the content to the target file. + * + * @param string $sourceFilePath Path of the file whose content will be copied + * @param resource $targetResource Target resource that will receive the content + * @return void + */ + protected function copyFileContentsToTarget($sourceFilePath, $targetResource) + { + $sourceHandle = fopen($sourceFilePath, 'r'); + stream_copy_to_stream($sourceHandle, $targetResource); + fclose($sourceHandle); + } + + /** + * Deletes the temporary folder where sheets content was stored. + * + * @return FileSystemHelper + */ + public function deleteWorksheetTempFolder() + { + $this->deleteFolderRecursively($this->sheetsContentTempFolder); + return $this; + } + + + /** + * Creates the "styles.xml" file under the root folder + * + * @param StyleHelper $styleHelper + * @param int $numWorksheets Number of created worksheets + * @return FileSystemHelper + */ + public function createStylesFile($styleHelper, $numWorksheets) + { + $stylesXmlFileContents = $styleHelper->getStylesXMLFileContent($numWorksheets); + $this->createFileWithContents($this->rootFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents); + + return $this; + } + + /** + * Zips the root folder and streams the contents of the zip into the given stream + * + * @param resource $streamPointer Pointer to the stream to copy the zip + * @return void + */ + public function zipRootFolderAndCopyToStream($streamPointer) + { + $zipHelper = new ZipHelper($this->rootFolder); + + // In order to have the file's mime type detected properly, files need to be added + // to the zip file in a particular order. + // @see http://www.jejik.com/articles/2010/03/how_to_correctly_create_odf_documents_using_zip/ + $zipHelper->addUncompressedFileToArchive($this->rootFolder, self::MIMETYPE_FILE_NAME); + + $zipHelper->addFolderToArchive($this->rootFolder, ZipHelper::EXISTING_FILES_SKIP); + $zipHelper->closeArchiveAndCopyToStream($streamPointer); + + // once the zip is copied, remove it + $this->deleteFile($zipHelper->getZipFilePath()); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/StyleHelper.php b/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/StyleHelper.php new file mode 100644 index 0000000000..f5ad3bc38e --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/ODS/Helper/StyleHelper.php @@ -0,0 +1,356 @@ + [] Map whose keys contain all the fonts used */ + protected $usedFontsSet = []; + + /** + * Registers the given style as a used style. + * Duplicate styles won't be registered more than once. + * + * @param \Box\Spout\Writer\Style\Style $style The style to be registered + * @return \Box\Spout\Writer\Style\Style The registered style, updated with an internal ID. + */ + public function registerStyle($style) + { + $this->usedFontsSet[$style->getFontName()] = true; + return parent::registerStyle($style); + } + + /** + * @return string[] List of used fonts name + */ + protected function getUsedFonts() + { + return array_keys($this->usedFontsSet); + } + + /** + * Returns the content of the "styles.xml" file, given a list of styles. + * + * @param int $numWorksheets Number of worksheets created + * @return string + */ + public function getStylesXMLFileContent($numWorksheets) + { + $content = << + +EOD; + + $content .= $this->getFontFaceSectionContent(); + $content .= $this->getStylesSectionContent(); + $content .= $this->getAutomaticStylesSectionContent($numWorksheets); + $content .= $this->getMasterStylesSectionContent($numWorksheets); + + $content .= << +EOD; + + return $content; + } + + /** + * Returns the content of the "" section, inside "styles.xml" file. + * + * @return string + */ + protected function getFontFaceSectionContent() + { + $content = ''; + foreach ($this->getUsedFonts() as $fontName) { + $content .= ''; + } + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section, inside "styles.xml" file. + * + * @return string + */ + protected function getStylesSectionContent() + { + $defaultStyle = $this->getDefaultStyle(); + + return << + + + + + + + + +EOD; + } + + /** + * Returns the content of the "" section, inside "styles.xml" file. + * + * @param int $numWorksheets Number of worksheets created + * @return string + */ + protected function getAutomaticStylesSectionContent($numWorksheets) + { + $content = ''; + + for ($i = 1; $i <= $numWorksheets; $i++) { + $content .= << + + + + +EOD; + } + + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section, inside "styles.xml" file. + * + * @param int $numWorksheets Number of worksheets created + * @return string + */ + protected function getMasterStylesSectionContent($numWorksheets) + { + $content = ''; + + for ($i = 1; $i <= $numWorksheets; $i++) { + $content .= << + + + + + +EOD; + } + + $content .= ''; + + return $content; + } + + + /** + * Returns the contents of the "" section, inside "content.xml" file. + * + * @return string + */ + public function getContentXmlFontFaceSectionContent() + { + $content = ''; + foreach ($this->getUsedFonts() as $fontName) { + $content .= ''; + } + $content .= ''; + + return $content; + } + + /** + * Returns the contents of the "" section, inside "content.xml" file. + * + * @param int $numWorksheets Number of worksheets created + * @return string + */ + public function getContentXmlAutomaticStylesSectionContent($numWorksheets) + { + $content = ''; + + foreach ($this->getRegisteredStyles() as $style) { + $content .= $this->getStyleSectionContent($style); + } + + $content .= << + + + + + +EOD; + + for ($i = 1; $i <= $numWorksheets; $i++) { + $content .= << + + +EOD; + } + + $content .= ''; + + return $content; + } + + /** + * Returns the contents of the "" section, inside "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + protected function getStyleSectionContent($style) + { + $styleIndex = $style->getId() + 1; // 1-based + + $content = ''; + + $content .= $this->getTextPropertiesSectionContent($style); + $content .= $this->getTableCellPropertiesSectionContent($style); + + $content .= ''; + + return $content; + } + + /** + * Returns the contents of the "" section, inside "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + private function getTextPropertiesSectionContent($style) + { + $content = ''; + + if ($style->shouldApplyFont()) { + $content .= $this->getFontSectionContent($style); + } + + return $content; + } + + /** + * Returns the contents of the "" section, inside "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + private function getFontSectionContent($style) + { + $defaultStyle = $this->getDefaultStyle(); + + $content = 'getFontColor(); + if ($fontColor !== $defaultStyle->getFontColor()) { + $content .= ' fo:color="#' . $fontColor . '"'; + } + + $fontName = $style->getFontName(); + if ($fontName !== $defaultStyle->getFontName()) { + $content .= ' style:font-name="' . $fontName . '" style:font-name-asian="' . $fontName . '" style:font-name-complex="' . $fontName . '"'; + } + + $fontSize = $style->getFontSize(); + if ($fontSize !== $defaultStyle->getFontSize()) { + $content .= ' fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt"'; + } + + if ($style->isFontBold()) { + $content .= ' fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"'; + } + if ($style->isFontItalic()) { + $content .= ' fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"'; + } + if ($style->isFontUnderline()) { + $content .= ' style:text-underline-style="solid" style:text-underline-type="single"'; + } + if ($style->isFontStrikethrough()) { + $content .= ' style:text-line-through-style="solid"'; + } + + $content .= '/>'; + + return $content; + } + + /** + * Returns the contents of the "" section, inside "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + private function getTableCellPropertiesSectionContent($style) + { + $content = ''; + + if ($style->shouldWrapText()) { + $content .= $this->getWrapTextXMLContent(); + } + + if ($style->shouldApplyBorder()) { + $content .= $this->getBorderXMLContent($style); + } + + if ($style->shouldApplyBackgroundColor()) { + $content .= $this->getBackgroundColorXMLContent($style); + } + + return $content; + } + + /** + * Returns the contents of the wrap text definition for the "" section + * + * @return string + */ + private function getWrapTextXMLContent() + { + return ''; + } + + /** + * Returns the contents of the borders definition for the "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + private function getBorderXMLContent($style) + { + $borderProperty = ''; + + $borders = array_map(function (BorderPart $borderPart) { + return BorderHelper::serializeBorderPart($borderPart); + }, $style->getBorder()->getParts()); + + return sprintf($borderProperty, implode(' ', $borders)); + } + + /** + * Returns the contents of the background color definition for the "" section + * + * @param \Box\Spout\Writer\Style\Style $style + * @return string + */ + private function getBackgroundColorXMLContent($style) + { + return sprintf( + '', + $style->getBackgroundColor() + ); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Workbook.php b/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Workbook.php new file mode 100644 index 0000000000..fc64ada824 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Workbook.php @@ -0,0 +1,119 @@ +fileSystemHelper = new FileSystemHelper($tempFolder); + $this->fileSystemHelper->createBaseFilesAndFolders(); + + $this->styleHelper = new StyleHelper($defaultRowStyle); + } + + /** + * @return \Box\Spout\Writer\ODS\Helper\StyleHelper Helper to apply styles to ODS files + */ + protected function getStyleHelper() + { + return $this->styleHelper; + } + + /** + * @return int Maximum number of rows/columns a sheet can contain + */ + protected function getMaxRowsPerWorksheet() + { + return self::$maxRowsPerWorksheet; + } + + /** + * Creates a new sheet in the workbook. The current sheet remains unchanged. + * + * @return Worksheet The created sheet + * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing + */ + public function addNewSheet() + { + $newSheetIndex = count($this->worksheets); + $sheet = new Sheet($newSheetIndex, $this->internalId); + + $sheetsContentTempFolder = $this->fileSystemHelper->getSheetsContentTempFolder(); + $worksheet = new Worksheet($sheet, $sheetsContentTempFolder); + $this->worksheets[] = $worksheet; + + return $worksheet; + } + + /** + * Closes the workbook and all its associated sheets. + * All the necessary files are written to disk and zipped together to create the ODS file. + * All the temporary files are then deleted. + * + * @param resource $finalFilePointer Pointer to the ODS that will be created + * @return void + */ + public function close($finalFilePointer) + { + /** @var Worksheet[] $worksheets */ + $worksheets = $this->worksheets; + $numWorksheets = count($worksheets); + + foreach ($worksheets as $worksheet) { + $worksheet->close(); + } + + // Finish creating all the necessary files before zipping everything together + $this->fileSystemHelper + ->createContentFile($worksheets, $this->styleHelper) + ->deleteWorksheetTempFolder() + ->createStylesFile($this->styleHelper, $numWorksheets) + ->zipRootFolderAndCopyToStream($finalFilePointer); + + $this->cleanupTempFolder(); + } + + /** + * Deletes the root folder created in the temp folder and all its contents. + * + * @return void + */ + protected function cleanupTempFolder() + { + $xlsxRootFolder = $this->fileSystemHelper->getRootFolder(); + $this->fileSystemHelper->deleteFolderRecursively($xlsxRootFolder); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Worksheet.php b/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Worksheet.php new file mode 100644 index 0000000000..0920b6dbaa --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/ODS/Internal/Worksheet.php @@ -0,0 +1,233 @@ +externalSheet = $externalSheet; + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->stringsEscaper = \Box\Spout\Common\Escaper\ODS::getInstance(); + $this->worksheetFilePath = $worksheetFilesFolder . '/sheet' . $externalSheet->getIndex() . '.xml'; + + $this->stringHelper = new StringHelper(); + + $this->startSheet(); + } + + /** + * Prepares the worksheet to accept data + * The XML file does not contain the "" node as it contains the sheet's name + * which may change during the execution of the program. It will be added at the end. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + protected function startSheet() + { + $this->sheetFilePointer = fopen($this->worksheetFilePath, 'w'); + $this->throwIfSheetFilePointerIsNotAvailable(); + } + + /** + * Checks if the book has been created. Throws an exception if not created yet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + protected function throwIfSheetFilePointerIsNotAvailable() + { + if (!$this->sheetFilePointer) { + throw new IOException('Unable to open sheet for writing.'); + } + } + + /** + * @return string Path to the temporary sheet content XML file + */ + public function getWorksheetFilePath() + { + return $this->worksheetFilePath; + } + + /** + * Returns the table XML root node as string. + * + * @return string node as string + */ + public function getTableElementStartAsString() + { + $escapedSheetName = $this->stringsEscaper->escape($this->externalSheet->getName()); + $tableStyleName = 'ta' . ($this->externalSheet->getIndex() + 1); + + $tableElement = ''; + $tableElement .= ''; + + return $tableElement; + } + + /** + * @return \Box\Spout\Writer\Common\Sheet The "external" sheet + */ + public function getExternalSheet() + { + return $this->externalSheet; + } + + /** + * @return int The index of the last written row + */ + public function getLastWrittenRowIndex() + { + return $this->lastWrittenRowIndex; + } + + /** + * Adds data to the worksheet. + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + */ + public function addRow($dataRow, $style) + { + // $dataRow can be an associative array. We need to transform + // it into a regular array, as we'll use the numeric indexes. + $dataRowWithNumericIndexes = array_values($dataRow); + + $styleIndex = ($style->getId() + 1); // 1-based + $cellsCount = count($dataRow); + $this->maxNumColumns = max($this->maxNumColumns, $cellsCount); + + $data = ''; + + $currentCellIndex = 0; + $nextCellIndex = 1; + + for ($i = 0; $i < $cellsCount; $i++) { + $currentCellValue = $dataRowWithNumericIndexes[$currentCellIndex]; + + // Using isset here because it is way faster than array_key_exists... + if (!isset($dataRowWithNumericIndexes[$nextCellIndex]) || + $currentCellValue !== $dataRowWithNumericIndexes[$nextCellIndex]) { + + $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex); + $data .= $this->getCellXML($currentCellValue, $styleIndex, $numTimesValueRepeated); + + $currentCellIndex = $nextCellIndex; + } + + $nextCellIndex++; + } + + $data .= ''; + + $wasWriteSuccessful = fwrite($this->sheetFilePointer, $data); + if ($wasWriteSuccessful === false) { + throw new IOException("Unable to write data in {$this->worksheetFilePath}"); + } + + // only update the count if the write worked + $this->lastWrittenRowIndex++; + } + + /** + * Returns the cell XML content, given its value. + * + * @param mixed $cellValue The value to be written + * @param int $styleIndex Index of the used style + * @param int $numTimesValueRepeated Number of times the value is consecutively repeated + * @return string The cell XML content + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + */ + protected function getCellXML($cellValue, $styleIndex, $numTimesValueRepeated) + { + $data = 'stringsEscaper->escape($cellValueLine) . ''; + } + + $data .= ''; + } else if (CellHelper::isBoolean($cellValue)) { + $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cellValue . '">'; + $data .= '' . $cellValue . ''; + $data .= ''; + } else if (CellHelper::isNumeric($cellValue)) { + $data .= ' office:value-type="float" calcext:value-type="float" office:value="' . $cellValue . '">'; + $data .= '' . $cellValue . ''; + $data .= ''; + } else if (empty($cellValue)) { + $data .= '/>'; + } else { + throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cellValue)); + } + + return $data; + } + + /** + * Closes the worksheet + * + * @return void + */ + public function close() + { + if (!is_resource($this->sheetFilePointer)) { + return; + } + + fclose($this->sheetFilePointer); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/ODS/Writer.php b/lib/vendor/box/spout/src/Spout/Writer/ODS/Writer.php new file mode 100644 index 0000000000..6571d0071d --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/ODS/Writer.php @@ -0,0 +1,93 @@ +throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->tempFolder = $tempFolder; + return $this; + } + + /** + * Configures the write and sets the current sheet pointer to a new sheet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to open the file for writing + */ + protected function openWriter() + { + $tempFolder = ($this->tempFolder) ? : sys_get_temp_dir(); + $this->book = new Workbook($tempFolder, $this->shouldCreateNewSheetsAutomatically, $this->defaultRowStyle); + $this->book->addNewSheetAndMakeItCurrent(); + } + + /** + * @return Internal\Workbook The workbook representing the file to be written + */ + protected function getWorkbook() + { + return $this->book; + } + + /** + * Adds data to the currently opened writer. + * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination + * with the creation of new worksheets if one worksheet has reached its maximum capicity. + * + * @param array $dataRow Array containing data to be written. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + protected function addRowToWriter(array $dataRow, $style) + { + $this->throwIfBookIsNotAvailable(); + $this->book->addRowToCurrentWorksheet($dataRow, $style); + } + + /** + * Closes the writer, preventing any additional writing. + * + * @return void + */ + protected function closeWriter() + { + if ($this->book) { + $this->book->close($this->filePointer); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/Border.php b/lib/vendor/box/spout/src/Spout/Writer/Style/Border.php new file mode 100644 index 0000000000..75f6a497bd --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/Border.php @@ -0,0 +1,85 @@ +setParts($borderParts); + } + + /** + * @param $name The name of the border part + * @return null|BorderPart + */ + public function getPart($name) + { + return $this->hasPart($name) ? $this->parts[$name] : null; + } + + /** + * @param $name The name of the border part + * @return bool + */ + public function hasPart($name) + { + return isset($this->parts[$name]); + } + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } + + /** + * Set BorderParts + * @param array $parts + */ + public function setParts($parts) + { + unset($this->parts); + foreach ($parts as $part) { + $this->addPart($part); + } + } + + /** + * @param BorderPart $borderPart + * @return self + */ + public function addPart(BorderPart $borderPart) + { + $this->parts[$borderPart->getName()] = $borderPart; + return $this; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/BorderBuilder.php b/lib/vendor/box/spout/src/Spout/Writer/Style/BorderBuilder.php new file mode 100644 index 0000000000..c0b8aea980 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/BorderBuilder.php @@ -0,0 +1,75 @@ +border = new Border(); + } + + /** + * @param string|void $color Border A RGB color code + * @param string|void $width Border width @see BorderPart::allowedWidths + * @param string|void $style Border style @see BorderPart::allowedStyles + * @return BorderBuilder + */ + public function setBorderTop($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID) + { + $this->border->addPart(new BorderPart(Border::TOP, $color, $width, $style)); + return $this; + } + + /** + * @param string|void $color Border A RGB color code + * @param string|void $width Border width @see BorderPart::allowedWidths + * @param string|void $style Border style @see BorderPart::allowedStyles + * @return BorderBuilder + */ + public function setBorderRight($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID) + { + $this->border->addPart(new BorderPart(Border::RIGHT, $color, $width, $style)); + return $this; + } + + /** + * @param string|void $color Border A RGB color code + * @param string|void $width Border width @see BorderPart::allowedWidths + * @param string|void $style Border style @see BorderPart::allowedStyles + * @return BorderBuilder + */ + public function setBorderBottom($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID) + { + $this->border->addPart(new BorderPart(Border::BOTTOM, $color, $width, $style)); + return $this; + } + + /** + * @param string|void $color Border A RGB color code + * @param string|void $width Border width @see BorderPart::allowedWidths + * @param string|void $style Border style @see BorderPart::allowedStyles + * @return BorderBuilder + */ + public function setBorderLeft($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID) + { + $this->border->addPart(new BorderPart(Border::LEFT, $color, $width, $style)); + return $this; + } + + /** + * @return Border + */ + public function build() + { + return $this->border; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/BorderPart.php b/lib/vendor/box/spout/src/Spout/Writer/Style/BorderPart.php new file mode 100644 index 0000000000..9ade797842 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/BorderPart.php @@ -0,0 +1,184 @@ +setName($name); + $this->setColor($color); + $this->setWidth($width); + $this->setStyle($style); + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name The name of the border part @see BorderPart::$allowedNames + * @throws InvalidNameException + * @return void + */ + public function setName($name) + { + if (!in_array($name, self::$allowedNames)) { + throw new InvalidNameException($name); + } + $this->name = $name; + } + + /** + * @return string + */ + public function getStyle() + { + return $this->style; + } + + /** + * @param string $style The style of the border part @see BorderPart::$allowedStyles + * @throws InvalidStyleException + * @return void + */ + public function setStyle($style) + { + if (!in_array($style, self::$allowedStyles)) { + throw new InvalidStyleException($style); + } + $this->style = $style; + } + + /** + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * @param string $color The color of the border part @see Color::rgb() + * @return void + */ + public function setColor($color) + { + $this->color = $color; + } + + /** + * @return string + */ + public function getWidth() + { + return $this->width; + } + + /** + * @param string $width The width of the border part @see BorderPart::$allowedWidths + * @throws InvalidWidthException + * @return void + */ + public function setWidth($width) + { + if (!in_array($width, self::$allowedWidths)) { + throw new InvalidWidthException($width); + } + $this->width = $width; + } + + /** + * @return array + */ + public static function getAllowedStyles() + { + return self::$allowedStyles; + } + + /** + * @return array + */ + public static function getAllowedNames() + { + return self::$allowedNames; + } + + /** + * @return array + */ + public static function getAllowedWidths() + { + return self::$allowedWidths; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/Color.php b/lib/vendor/box/spout/src/Spout/Writer/Style/Color.php new file mode 100644 index 0000000000..3c86eb706b --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/Color.php @@ -0,0 +1,87 @@ + 255) { + throw new InvalidColorException("The RGB components must be between 0 and 255. Received: $colorComponent"); + } + } + + /** + * Converts the color component to its corresponding hexadecimal value + * + * @param int $colorComponent Color component, 0 - 255 + * @return string Corresponding hexadecimal value, with a leading 0 if needed. E.g "0f", "2d" + */ + protected static function convertColorComponentToHex($colorComponent) + { + return str_pad(dechex($colorComponent), 2, '0', STR_PAD_LEFT); + } + + /** + * Returns the ARGB color of the given RGB color, + * assuming that alpha value is always 1. + * + * @param string $rgbColor RGB color like "FF08B2" + * @return string ARGB color + */ + public static function toARGB($rgbColor) + { + return 'FF' . $rgbColor; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/Style.php b/lib/vendor/box/spout/src/Spout/Writer/Style/Style.php new file mode 100644 index 0000000000..b408ad3ca1 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/Style.php @@ -0,0 +1,426 @@ +id; + } + + /** + * @param int $id + * @return Style + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * @return Border + */ + public function getBorder() + { + return $this->border; + } + + /** + * @param Border $border + * @return Style + */ + public function setBorder(Border $border) + { + $this->shouldApplyBorder = true; + $this->border = $border; + return $this; + } + + /** + * @return bool + */ + public function shouldApplyBorder() + { + return $this->shouldApplyBorder; + } + + /** + * @return bool + */ + public function isFontBold() + { + return $this->fontBold; + } + + /** + * @return Style + */ + public function setFontBold() + { + $this->fontBold = true; + $this->hasSetFontBold = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return bool + */ + public function isFontItalic() + { + return $this->fontItalic; + } + + /** + * @return Style + */ + public function setFontItalic() + { + $this->fontItalic = true; + $this->hasSetFontItalic = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return bool + */ + public function isFontUnderline() + { + return $this->fontUnderline; + } + + /** + * @return Style + */ + public function setFontUnderline() + { + $this->fontUnderline = true; + $this->hasSetFontUnderline = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return bool + */ + public function isFontStrikethrough() + { + return $this->fontStrikethrough; + } + + /** + * @return Style + */ + public function setFontStrikethrough() + { + $this->fontStrikethrough = true; + $this->hasSetFontStrikethrough = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return int + */ + public function getFontSize() + { + return $this->fontSize; + } + + /** + * @param int $fontSize Font size, in pixels + * @return Style + */ + public function setFontSize($fontSize) + { + $this->fontSize = $fontSize; + $this->hasSetFontSize = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return string + */ + public function getFontColor() + { + return $this->fontColor; + } + + /** + * Sets the font color. + * + * @param string $fontColor ARGB color (@see Color) + * @return Style + */ + public function setFontColor($fontColor) + { + $this->fontColor = $fontColor; + $this->hasSetFontColor = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return string + */ + public function getFontName() + { + return $this->fontName; + } + + /** + * @param string $fontName Name of the font to use + * @return Style + */ + public function setFontName($fontName) + { + $this->fontName = $fontName; + $this->hasSetFontName = true; + $this->shouldApplyFont = true; + return $this; + } + + /** + * @return bool + */ + public function shouldWrapText() + { + return $this->shouldWrapText; + } + + /** + * @param bool|void $shouldWrap Should the text be wrapped + * @return Style + */ + public function setShouldWrapText($shouldWrap = true) + { + $this->shouldWrapText = $shouldWrap; + $this->hasSetWrapText = true; + return $this; + } + + /** + * @return bool + */ + public function hasSetWrapText() + { + return $this->hasSetWrapText; + } + + /** + * @return bool Whether specific font properties should be applied + */ + public function shouldApplyFont() + { + return $this->shouldApplyFont; + } + + /** + * Sets the background color + * @param string $color ARGB color (@see Color) + * @return Style + */ + public function setBackgroundColor($color) + { + $this->hasSetBackgroundColor = true; + $this->backgroundColor = $color; + return $this; + } + + /** + * @return string + */ + public function getBackgroundColor() + { + return $this->backgroundColor; + } + + /** + * + * @return bool Whether the background color should be applied + */ + public function shouldApplyBackgroundColor() + { + return $this->hasSetBackgroundColor; + } + + /** + * Serializes the style for future comparison with other styles. + * The ID is excluded from the comparison, as we only care about + * actual style properties. + * + * @return string The serialized style + */ + public function serialize() + { + // In order to be able to properly compare style, set static ID value + $currentId = $this->id; + $this->setId(0); + + $serializedStyle = serialize($this); + + $this->setId($currentId); + + return $serializedStyle; + } + + /** + * Merges the current style with the given style, using the given style as a base. This means that: + * - if current style and base style both have property A set, use current style property's value + * - if current style has property A set but base style does not, use current style property's value + * - if base style has property A set but current style does not, use base style property's value + * + * @NOTE: This function returns a new style. + * + * @param Style $baseStyle + * @return Style New style corresponding to the merge of the 2 styles + */ + public function mergeWith($baseStyle) + { + $mergedStyle = clone $this; + + $this->mergeFontStyles($mergedStyle, $baseStyle); + $this->mergeOtherFontProperties($mergedStyle, $baseStyle); + $this->mergeCellProperties($mergedStyle, $baseStyle); + + return $mergedStyle; + } + + /** + * @param Style $styleToUpdate (passed as reference) + * @param Style $baseStyle + * @return void + */ + private function mergeFontStyles($styleToUpdate, $baseStyle) + { + if (!$this->hasSetFontBold && $baseStyle->isFontBold()) { + $styleToUpdate->setFontBold(); + } + if (!$this->hasSetFontItalic && $baseStyle->isFontItalic()) { + $styleToUpdate->setFontItalic(); + } + if (!$this->hasSetFontUnderline && $baseStyle->isFontUnderline()) { + $styleToUpdate->setFontUnderline(); + } + if (!$this->hasSetFontStrikethrough && $baseStyle->isFontStrikethrough()) { + $styleToUpdate->setFontStrikethrough(); + } + } + + /** + * @param Style $styleToUpdate Style to update (passed as reference) + * @param Style $baseStyle + * @return void + */ + private function mergeOtherFontProperties($styleToUpdate, $baseStyle) + { + if (!$this->hasSetFontSize && $baseStyle->getFontSize() !== self::DEFAULT_FONT_SIZE) { + $styleToUpdate->setFontSize($baseStyle->getFontSize()); + } + if (!$this->hasSetFontColor && $baseStyle->getFontColor() !== self::DEFAULT_FONT_COLOR) { + $styleToUpdate->setFontColor($baseStyle->getFontColor()); + } + if (!$this->hasSetFontName && $baseStyle->getFontName() !== self::DEFAULT_FONT_NAME) { + $styleToUpdate->setFontName($baseStyle->getFontName()); + } + } + + /** + * @param Style $styleToUpdate Style to update (passed as reference) + * @param Style $baseStyle + * @return void + */ + private function mergeCellProperties($styleToUpdate, $baseStyle) + { + if (!$this->hasSetWrapText && $baseStyle->shouldWrapText()) { + $styleToUpdate->setShouldWrapText(); + } + if (!$this->getBorder() && $baseStyle->shouldApplyBorder()) { + $styleToUpdate->setBorder($baseStyle->getBorder()); + } + if (!$this->hasSetBackgroundColor && $baseStyle->shouldApplyBackgroundColor()) { + $styleToUpdate->setBackgroundColor($baseStyle->getBackgroundColor()); + } + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/Style/StyleBuilder.php b/lib/vendor/box/spout/src/Spout/Writer/Style/StyleBuilder.php new file mode 100644 index 0000000000..2676cbe6fc --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/Style/StyleBuilder.php @@ -0,0 +1,159 @@ +style = new Style(); + } + + /** + * Makes the font bold. + * + * @api + * @return StyleBuilder + */ + public function setFontBold() + { + $this->style->setFontBold(); + return $this; + } + + /** + * Makes the font italic. + * + * @api + * @return StyleBuilder + */ + public function setFontItalic() + { + $this->style->setFontItalic(); + return $this; + } + + /** + * Makes the font underlined. + * + * @api + * @return StyleBuilder + */ + public function setFontUnderline() + { + $this->style->setFontUnderline(); + return $this; + } + + /** + * Makes the font struck through. + * + * @api + * @return StyleBuilder + */ + public function setFontStrikethrough() + { + $this->style->setFontStrikethrough(); + return $this; + } + + /** + * Sets the font size. + * + * @api + * @param int $fontSize Font size, in pixels + * @return StyleBuilder + */ + public function setFontSize($fontSize) + { + $this->style->setFontSize($fontSize); + return $this; + } + + /** + * Sets the font color. + * + * @api + * @param string $fontColor ARGB color (@see Color) + * @return StyleBuilder + */ + public function setFontColor($fontColor) + { + $this->style->setFontColor($fontColor); + return $this; + } + + /** + * Sets the font name. + * + * @api + * @param string $fontName Name of the font to use + * @return StyleBuilder + */ + public function setFontName($fontName) + { + $this->style->setFontName($fontName); + return $this; + } + + /** + * Makes the text wrap in the cell if requested + * + * @api + * @param bool $shouldWrap Should the text be wrapped + * @return StyleBuilder + */ + public function setShouldWrapText($shouldWrap = true) + { + $this->style->setShouldWrapText($shouldWrap); + return $this; + } + + /** + * Set a border + * + * @param Border $border + * @return $this + */ + public function setBorder(Border $border) + { + $this->style->setBorder($border); + return $this; + } + + /** + * Sets a background color + * + * @api + * @param string $color ARGB color (@see Color) + * @return StyleBuilder + */ + public function setBackgroundColor($color) + { + $this->style->setBackgroundColor($color); + return $this; + } + + /** + * Returns the configured style. The style is cached and can be reused. + * + * @api + * @return Style + */ + public function build() + { + return $this->style; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/WriterFactory.php b/lib/vendor/box/spout/src/Spout/Writer/WriterFactory.php new file mode 100644 index 0000000000..7588940c7c --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/WriterFactory.php @@ -0,0 +1,48 @@ +setGlobalFunctionsHelper(new GlobalFunctionsHelper()); + + return $writer; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/WriterInterface.php b/lib/vendor/box/spout/src/Spout/Writer/WriterInterface.php new file mode 100644 index 0000000000..93a6ee24b6 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/WriterInterface.php @@ -0,0 +1,91 @@ + [ + Border::WIDTH_THIN => 'thin', + Border::WIDTH_MEDIUM => 'medium', + Border::WIDTH_THICK => 'thick' + ], + Border::STYLE_DOTTED => [ + Border::WIDTH_THIN => 'dotted', + Border::WIDTH_MEDIUM => 'dotted', + Border::WIDTH_THICK => 'dotted', + ], + Border::STYLE_DASHED => [ + Border::WIDTH_THIN => 'dashed', + Border::WIDTH_MEDIUM => 'mediumDashed', + Border::WIDTH_THICK => 'mediumDashed', + ], + Border::STYLE_DOUBLE => [ + Border::WIDTH_THIN => 'double', + Border::WIDTH_MEDIUM => 'double', + Border::WIDTH_THICK => 'double', + ], + Border::STYLE_NONE => [ + Border::WIDTH_THIN => 'none', + Border::WIDTH_MEDIUM => 'none', + Border::WIDTH_THICK => 'none', + ], + ]; + + /** + * @param BorderPart $borderPart + * @return string + */ + public static function serializeBorderPart(BorderPart $borderPart) + { + $borderStyle = self::getBorderStyle($borderPart); + + $colorEl = $borderPart->getColor() ? sprintf('', $borderPart->getColor()) : ''; + $partEl = sprintf( + '<%s style="%s">%s', + $borderPart->getName(), + $borderStyle, + $colorEl, + $borderPart->getName() + ); + + return $partEl . PHP_EOL; + } + + /** + * Get the style definition from the style map + * + * @param BorderPart $borderPart + * @return string + */ + protected static function getBorderStyle(BorderPart $borderPart) + { + return self::$xlsxStyleMap[$borderPart->getStyle()][$borderPart->getWidth()]; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php new file mode 100644 index 0000000000..86515f30c5 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php @@ -0,0 +1,371 @@ +rootFolder; + } + + /** + * @return string + */ + public function getXlFolder() + { + return $this->xlFolder; + } + + /** + * @return string + */ + public function getXlWorksheetsFolder() + { + return $this->xlWorksheetsFolder; + } + + /** + * Creates all the folders needed to create a XLSX file, as well as the files that won't change. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to create at least one of the base folders + */ + public function createBaseFilesAndFolders() + { + $this + ->createRootFolder() + ->createRelsFolderAndFile() + ->createDocPropsFolderAndFiles() + ->createXlFolderAndSubFolders(); + } + + /** + * Creates the folder that will be used as root + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder + */ + protected function createRootFolder() + { + $this->rootFolder = $this->createFolder($this->baseFolderRealPath, uniqid('xlsx', true)); + return $this; + } + + /** + * Creates the "_rels" folder under the root folder as well as the ".rels" file in it + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or the ".rels" file + */ + protected function createRelsFolderAndFile() + { + $this->relsFolder = $this->createFolder($this->rootFolder, self::RELS_FOLDER_NAME); + + $this->createRelsFile(); + + return $this; + } + + /** + * Creates the ".rels" file under the "_rels" folder (under root) + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createRelsFile() + { + $relsFileContents = << + + + + + +EOD; + + $this->createFileWithContents($this->relsFolder, self::RELS_FILE_NAME, $relsFileContents); + + return $this; + } + + /** + * Creates the "docProps" folder under the root folder as well as the "app.xml" and "core.xml" files in it + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or one of the files + */ + protected function createDocPropsFolderAndFiles() + { + $this->docPropsFolder = $this->createFolder($this->rootFolder, self::DOC_PROPS_FOLDER_NAME); + + $this->createAppXmlFile(); + $this->createCoreXmlFile(); + + return $this; + } + + /** + * Creates the "app.xml" file under the "docProps" folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createAppXmlFile() + { + $appName = self::APP_NAME; + $appXmlFileContents = << + + $appName + 0 + +EOD; + + $this->createFileWithContents($this->docPropsFolder, self::APP_XML_FILE_NAME, $appXmlFileContents); + + return $this; + } + + /** + * Creates the "core.xml" file under the "docProps" folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the file + */ + protected function createCoreXmlFile() + { + $createdDate = (new \DateTime())->format(\DateTime::W3C); + $coreXmlFileContents = << + + $createdDate + $createdDate + 0 + +EOD; + + $this->createFileWithContents($this->docPropsFolder, self::CORE_XML_FILE_NAME, $coreXmlFileContents); + + return $this; + } + + /** + * Creates the "xl" folder under the root folder as well as its subfolders + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create at least one of the folders + */ + protected function createXlFolderAndSubFolders() + { + $this->xlFolder = $this->createFolder($this->rootFolder, self::XL_FOLDER_NAME); + $this->createXlRelsFolder(); + $this->createXlWorksheetsFolder(); + + return $this; + } + + /** + * Creates the "_rels" folder under the "xl" folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder + */ + protected function createXlRelsFolder() + { + $this->xlRelsFolder = $this->createFolder($this->xlFolder, self::RELS_FOLDER_NAME); + return $this; + } + + /** + * Creates the "worksheets" folder under the "xl" folder + * + * @return FileSystemHelper + * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder + */ + protected function createXlWorksheetsFolder() + { + $this->xlWorksheetsFolder = $this->createFolder($this->xlFolder, self::WORKSHEETS_FOLDER_NAME); + return $this; + } + + /** + * Creates the "[Content_Types].xml" file under the root folder + * + * @param Worksheet[] $worksheets + * @return FileSystemHelper + */ + public function createContentTypesFile($worksheets) + { + $contentTypesXmlFileContents = << + + + + +EOD; + + /** @var Worksheet $worksheet */ + foreach ($worksheets as $worksheet) { + $contentTypesXmlFileContents .= ''; + } + + $contentTypesXmlFileContents .= << + + + + +EOD; + + $this->createFileWithContents($this->rootFolder, self::CONTENT_TYPES_XML_FILE_NAME, $contentTypesXmlFileContents); + + return $this; + } + + /** + * Creates the "workbook.xml" file under the "xl" folder + * + * @param Worksheet[] $worksheets + * @return FileSystemHelper + */ + public function createWorkbookFile($worksheets) + { + $workbookXmlFileContents = << + + +EOD; + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $escaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); + + /** @var Worksheet $worksheet */ + foreach ($worksheets as $worksheet) { + $worksheetName = $worksheet->getExternalSheet()->getName(); + $worksheetId = $worksheet->getId(); + $workbookXmlFileContents .= ''; + } + + $workbookXmlFileContents .= << + +EOD; + + $this->createFileWithContents($this->xlFolder, self::WORKBOOK_XML_FILE_NAME, $workbookXmlFileContents); + + return $this; + } + + /** + * Creates the "workbook.xml.res" file under the "xl/_res" folder + * + * @param Worksheet[] $worksheets + * @return FileSystemHelper + */ + public function createWorkbookRelsFile($worksheets) + { + $workbookRelsXmlFileContents = << + + + +EOD; + + /** @var Worksheet $worksheet */ + foreach ($worksheets as $worksheet) { + $worksheetId = $worksheet->getId(); + $workbookRelsXmlFileContents .= ''; + } + + $workbookRelsXmlFileContents .= ''; + + $this->createFileWithContents($this->xlRelsFolder, self::WORKBOOK_RELS_XML_FILE_NAME, $workbookRelsXmlFileContents); + + return $this; + } + + /** + * Creates the "styles.xml" file under the "xl" folder + * + * @param StyleHelper $styleHelper + * @return FileSystemHelper + */ + public function createStylesFile($styleHelper) + { + $stylesXmlFileContents = $styleHelper->getStylesXMLFileContent(); + $this->createFileWithContents($this->xlFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents); + + return $this; + } + + /** + * Zips the root folder and streams the contents of the zip into the given stream + * + * @param resource $streamPointer Pointer to the stream to copy the zip + * @return void + */ + public function zipRootFolderAndCopyToStream($streamPointer) + { + $zipHelper = new ZipHelper($this->rootFolder); + + // In order to have the file's mime type detected properly, files need to be added + // to the zip file in a particular order. + // "[Content_Types].xml" then at least 2 files located in "xl" folder should be zipped first. + $zipHelper->addFileToArchive($this->rootFolder, self::CONTENT_TYPES_XML_FILE_NAME); + $zipHelper->addFileToArchive($this->rootFolder, self::XL_FOLDER_NAME . '/' . self::WORKBOOK_XML_FILE_NAME); + $zipHelper->addFileToArchive($this->rootFolder, self::XL_FOLDER_NAME . '/' . self::STYLES_XML_FILE_NAME); + + $zipHelper->addFolderToArchive($this->rootFolder, ZipHelper::EXISTING_FILES_SKIP); + $zipHelper->closeArchiveAndCopyToStream($streamPointer); + + // once the zip is copied, remove it + $this->deleteFile($zipHelper->getZipFilePath()); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/SharedStringsHelper.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/SharedStringsHelper.php new file mode 100644 index 0000000000..292b663ce8 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/SharedStringsHelper.php @@ -0,0 +1,107 @@ + +sharedStringsFilePointer = fopen($sharedStringsFilePath, 'w'); + + $this->throwIfSharedStringsFilePointerIsNotAvailable(); + + // the headers is split into different parts so that we can fseek and put in the correct count and uniqueCount later + $header = self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER . ' ' . self::DEFAULT_STRINGS_COUNT_PART . '>'; + fwrite($this->sharedStringsFilePointer, $header); + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); + } + + /** + * Checks if the book has been created. Throws an exception if not created yet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + protected function throwIfSharedStringsFilePointerIsNotAvailable() + { + if (!$this->sharedStringsFilePointer) { + throw new IOException('Unable to open shared strings file for writing.'); + } + } + + /** + * Writes the given string into the sharedStrings.xml file. + * Starting and ending whitespaces are preserved. + * + * @param string $string + * @return int ID of the written shared string + */ + public function writeString($string) + { + fwrite($this->sharedStringsFilePointer, '' . $this->stringsEscaper->escape($string) . ''); + $this->numSharedStrings++; + + // Shared string ID is zero-based + return ($this->numSharedStrings - 1); + } + + /** + * Finishes writing the data in the sharedStrings.xml file and closes the file. + * + * @return void + */ + public function close() + { + if (!is_resource($this->sharedStringsFilePointer)) { + return; + } + + fwrite($this->sharedStringsFilePointer, ''); + + // Replace the default strings count with the actual number of shared strings in the file header + $firstPartHeaderLength = strlen(self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER); + $defaultStringsCountPartLength = strlen(self::DEFAULT_STRINGS_COUNT_PART); + + // Adding 1 to take into account the space between the last xml attribute and "count" + fseek($this->sharedStringsFilePointer, $firstPartHeaderLength + 1); + fwrite($this->sharedStringsFilePointer, sprintf("%-{$defaultStringsCountPartLength}s", 'count="' . $this->numSharedStrings . '" uniqueCount="' . $this->numSharedStrings . '"')); + + fclose($this->sharedStringsFilePointer); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/StyleHelper.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/StyleHelper.php new file mode 100644 index 0000000000..4a13c9562f --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Helper/StyleHelper.php @@ -0,0 +1,344 @@ + [FILL_ID] maps a style to a fill declaration + */ + protected $styleIdToFillMappingTable = []; + + /** + * Excel preserves two default fills with index 0 and 1 + * Since Excel is the dominant vendor - we play along here + * + * @var int The fill index counter for custom fills. + */ + protected $fillIndex = 2; + + /** + * @var array + */ + protected $registeredBorders = []; + + /** + * @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration + */ + protected $styleIdToBorderMappingTable = []; + + /** + * XLSX specific operations on the registered styles + * + * @param \Box\Spout\Writer\Style\Style $style + * @return \Box\Spout\Writer\Style\Style + */ + public function registerStyle($style) + { + $registeredStyle = parent::registerStyle($style); + $this->registerFill($registeredStyle); + $this->registerBorder($registeredStyle); + return $registeredStyle; + } + + /** + * Register a fill definition + * + * @param \Box\Spout\Writer\Style\Style $style + */ + protected function registerFill($style) + { + $styleId = $style->getId(); + + // Currently - only solid backgrounds are supported + // so $backgroundColor is a scalar value (RGB Color) + $backgroundColor = $style->getBackgroundColor(); + + if ($backgroundColor) { + $isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]); + + // We need to track the already registered background definitions + if ($isBackgroundColorRegistered) { + $registeredStyleId = $this->registeredFills[$backgroundColor]; + $registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId]; + $this->styleIdToFillMappingTable[$styleId] = $registeredFillId; + } else { + $this->registeredFills[$backgroundColor] = $styleId; + $this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++; + } + + } else { + // The fillId maps a style to a fill declaration + // When there is no background color definition - we default to 0 + $this->styleIdToFillMappingTable[$styleId] = 0; + } + } + + /** + * Register a border definition + * + * @param \Box\Spout\Writer\Style\Style $style + */ + protected function registerBorder($style) + { + $styleId = $style->getId(); + + if ($style->shouldApplyBorder()) { + $border = $style->getBorder(); + $serializedBorder = serialize($border); + + $isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]); + + if ($isBorderAlreadyRegistered) { + $registeredStyleId = $this->registeredBorders[$serializedBorder]; + $registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId]; + $this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId; + } else { + $this->registeredBorders[$serializedBorder] = $styleId; + $this->styleIdToBorderMappingTable[$styleId] = count($this->registeredBorders); + } + + } else { + // If no border should be applied - the mapping is the default border: 0 + $this->styleIdToBorderMappingTable[$styleId] = 0; + } + } + + + /** + * For empty cells, we can specify a style or not. If no style are specified, + * then the software default will be applied. But sometimes, it may be useful + * to override this default style, for instance if the cell should have a + * background color different than the default one or some borders + * (fonts property don't really matter here). + * + * @param int $styleId + * @return bool Whether the cell should define a custom style + */ + public function shouldApplyStyleOnEmptyCell($styleId) + { + $hasStyleCustomFill = (isset($this->styleIdToFillMappingTable[$styleId]) && $this->styleIdToFillMappingTable[$styleId] !== 0); + $hasStyleCustomBorders = (isset($this->styleIdToBorderMappingTable[$styleId]) && $this->styleIdToBorderMappingTable[$styleId] !== 0); + + return ($hasStyleCustomFill || $hasStyleCustomBorders); + } + + + /** + * Returns the content of the "styles.xml" file, given a list of styles. + * + * @return string + */ + public function getStylesXMLFileContent() + { + $content = << + +EOD; + + $content .= $this->getFontsSectionContent(); + $content .= $this->getFillsSectionContent(); + $content .= $this->getBordersSectionContent(); + $content .= $this->getCellStyleXfsSectionContent(); + $content .= $this->getCellXfsSectionContent(); + $content .= $this->getCellStylesSectionContent(); + + $content .= << +EOD; + + return $content; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getFontsSectionContent() + { + $content = ''; + + /** @var \Box\Spout\Writer\Style\Style $style */ + foreach ($this->getRegisteredStyles() as $style) { + $content .= ''; + + $content .= ''; + $content .= ''; + $content .= ''; + + if ($style->isFontBold()) { + $content .= ''; + } + if ($style->isFontItalic()) { + $content .= ''; + } + if ($style->isFontUnderline()) { + $content .= ''; + } + if ($style->isFontStrikethrough()) { + $content .= ''; + } + + $content .= ''; + } + + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getFillsSectionContent() + { + // Excel reserves two default fills + $fillsCount = count($this->registeredFills) + 2; + $content = sprintf('', $fillsCount); + + $content .= ''; + $content .= ''; + + // The other fills are actually registered by setting a background color + foreach ($this->registeredFills as $styleId) { + /** @var Style $style */ + $style = $this->styleIdToStyleMappingTable[$styleId]; + + $backgroundColor = $style->getBackgroundColor(); + $content .= sprintf( + '', + $backgroundColor + ); + } + + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getBordersSectionContent() + { + + // There is one default border with index 0 + $borderCount = count($this->registeredBorders) + 1; + + $content = ''; + + // Default border starting at index 0 + $content .= ''; + + foreach ($this->registeredBorders as $styleId) { + /** @var \Box\Spout\Writer\Style\Style $style */ + $style = $this->styleIdToStyleMappingTable[$styleId]; + $border = $style->getBorder(); + $content .= ''; + + // @link https://github.com/box/spout/issues/271 + $sortOrder = ['left', 'right', 'top', 'bottom']; + + foreach ($sortOrder as $partName) { + if ($border->hasPart($partName)) { + /** @var $part \Box\Spout\Writer\Style\BorderPart */ + $part = $border->getPart($partName); + $content .= BorderHelper::serializeBorderPart($part); + } + + } + + $content .= ''; + } + + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getCellStyleXfsSectionContent() + { + return << + + +EOD; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getCellXfsSectionContent() + { + $registeredStyles = $this->getRegisteredStyles(); + + $content = ''; + + foreach ($registeredStyles as $style) { + $styleId = $style->getId(); + $fillId = $this->styleIdToFillMappingTable[$styleId]; + $borderId = $this->styleIdToBorderMappingTable[$styleId]; + + $content .= 'shouldApplyFont()) { + $content .= ' applyFont="1"'; + } + + $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0); + + if ($style->shouldWrapText()) { + $content .= ' applyAlignment="1">'; + $content .= ''; + $content .= ''; + } else { + $content .= '/>'; + } + } + + $content .= ''; + + return $content; + } + + /** + * Returns the content of the "" section. + * + * @return string + */ + protected function getCellStylesSectionContent() + { + return << + + +EOD; + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Workbook.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Workbook.php new file mode 100644 index 0000000000..bcdce7f725 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Workbook.php @@ -0,0 +1,135 @@ +shouldUseInlineStrings = $shouldUseInlineStrings; + + $this->fileSystemHelper = new FileSystemHelper($tempFolder); + $this->fileSystemHelper->createBaseFilesAndFolders(); + + $this->styleHelper = new StyleHelper($defaultRowStyle); + + // This helper will be shared by all sheets + $xlFolder = $this->fileSystemHelper->getXlFolder(); + $this->sharedStringsHelper = new SharedStringsHelper($xlFolder); + } + + /** + * @return \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to apply styles to XLSX files + */ + protected function getStyleHelper() + { + return $this->styleHelper; + } + + /** + * @return int Maximum number of rows/columns a sheet can contain + */ + protected function getMaxRowsPerWorksheet() + { + return self::$maxRowsPerWorksheet; + } + + /** + * Creates a new sheet in the workbook. The current sheet remains unchanged. + * + * @return Worksheet The created sheet + * @throws \Box\Spout\Common\Exception\IOException If unable to open the sheet for writing + */ + public function addNewSheet() + { + $newSheetIndex = count($this->worksheets); + $sheet = new Sheet($newSheetIndex, $this->internalId); + + $worksheetFilesFolder = $this->fileSystemHelper->getXlWorksheetsFolder(); + $worksheet = new Worksheet($sheet, $worksheetFilesFolder, $this->sharedStringsHelper, $this->styleHelper, $this->shouldUseInlineStrings); + $this->worksheets[] = $worksheet; + + return $worksheet; + } + + /** + * Closes the workbook and all its associated sheets. + * All the necessary files are written to disk and zipped together to create the XLSX file. + * All the temporary files are then deleted. + * + * @param resource $finalFilePointer Pointer to the XLSX that will be created + * @return void + */ + public function close($finalFilePointer) + { + /** @var Worksheet[] $worksheets */ + $worksheets = $this->worksheets; + + foreach ($worksheets as $worksheet) { + $worksheet->close(); + } + + $this->sharedStringsHelper->close(); + + // Finish creating all the necessary files before zipping everything together + $this->fileSystemHelper + ->createContentTypesFile($worksheets) + ->createWorkbookFile($worksheets) + ->createWorkbookRelsFile($worksheets) + ->createStylesFile($this->styleHelper) + ->zipRootFolderAndCopyToStream($finalFilePointer); + + $this->cleanupTempFolder(); + } + + /** + * Deletes the root folder created in the temp folder and all its contents. + * + * @return void + */ + protected function cleanupTempFolder() + { + $xlsxRootFolder = $this->fileSystemHelper->getRootFolder(); + $this->fileSystemHelper->deleteFolderRecursively($xlsxRootFolder); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Worksheet.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Worksheet.php new file mode 100644 index 0000000000..0bd909d184 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Internal/Worksheet.php @@ -0,0 +1,275 @@ + + +EOD; + + /** @var \Box\Spout\Writer\Common\Sheet The "external" sheet */ + protected $externalSheet; + + /** @var string Path to the XML file that will contain the sheet data */ + protected $worksheetFilePath; + + /** @var \Box\Spout\Writer\XLSX\Helper\SharedStringsHelper Helper to write shared strings */ + protected $sharedStringsHelper; + + /** @var \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to work with styles */ + protected $styleHelper; + + /** @var bool Whether inline or shared strings should be used */ + protected $shouldUseInlineStrings; + + /** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */ + protected $stringsEscaper; + + /** @var \Box\Spout\Common\Helper\StringHelper String helper */ + protected $stringHelper; + + /** @var Resource Pointer to the sheet data file (e.g. xl/worksheets/sheet1.xml) */ + protected $sheetFilePointer; + + /** @var int Index of the last written row */ + protected $lastWrittenRowIndex = 0; + + /** + * @param \Box\Spout\Writer\Common\Sheet $externalSheet The associated "external" sheet + * @param string $worksheetFilesFolder Temporary folder where the files to create the XLSX will be stored + * @param \Box\Spout\Writer\XLSX\Helper\SharedStringsHelper $sharedStringsHelper Helper for shared strings + * @param \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to work with styles + * @param bool $shouldUseInlineStrings Whether inline or shared strings should be used + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + public function __construct($externalSheet, $worksheetFilesFolder, $sharedStringsHelper, $styleHelper, $shouldUseInlineStrings) + { + $this->externalSheet = $externalSheet; + $this->sharedStringsHelper = $sharedStringsHelper; + $this->styleHelper = $styleHelper; + $this->shouldUseInlineStrings = $shouldUseInlineStrings; + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + $this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance(); + $this->stringHelper = new StringHelper(); + + $this->worksheetFilePath = $worksheetFilesFolder . '/' . strtolower($this->externalSheet->getName()) . '.xml'; + $this->startSheet(); + } + + /** + * Prepares the worksheet to accept data + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + protected function startSheet() + { + $this->sheetFilePointer = fopen($this->worksheetFilePath, 'w'); + $this->throwIfSheetFilePointerIsNotAvailable(); + + fwrite($this->sheetFilePointer, self::SHEET_XML_FILE_HEADER); + fwrite($this->sheetFilePointer, ''); + } + + /** + * Checks if the book has been created. Throws an exception if not created yet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing + */ + protected function throwIfSheetFilePointerIsNotAvailable() + { + if (!$this->sheetFilePointer) { + throw new IOException('Unable to open sheet for writing.'); + } + } + + /** + * @return \Box\Spout\Writer\Common\Sheet The "external" sheet + */ + public function getExternalSheet() + { + return $this->externalSheet; + } + + /** + * @return int The index of the last written row + */ + public function getLastWrittenRowIndex() + { + return $this->lastWrittenRowIndex; + } + + /** + * @return int The ID of the worksheet + */ + public function getId() + { + // sheet index is zero-based, while ID is 1-based + return $this->externalSheet->getIndex() + 1; + } + + /** + * Adds data to the worksheet. + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + */ + public function addRow($dataRow, $style) + { + if (!$this->isEmptyRow($dataRow)) { + $this->addNonEmptyRow($dataRow, $style); + } + + $this->lastWrittenRowIndex++; + } + + /** + * Returns whether the given row is empty + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @return bool Whether the given row is empty + */ + protected function isEmptyRow($dataRow) + { + $numCells = count($dataRow); + // using "reset()" instead of "$dataRow[0]" because $dataRow can be an associative array + return ($numCells === 1 && CellHelper::isEmpty(reset($dataRow))); + } + + /** + * Adds non empty row to the worksheet. + * + * @param array $dataRow Array containing data to be written. Cannot be empty. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. NULL means use default style. + * @return void + * @throws \Box\Spout\Common\Exception\IOException If the data cannot be written + * @throws \Box\Spout\Common\Exception\InvalidArgumentException If a cell value's type is not supported + */ + protected function addNonEmptyRow($dataRow, $style) + { + $cellNumber = 0; + $rowIndex = $this->lastWrittenRowIndex + 1; + $numCells = count($dataRow); + + $rowXML = ''; + + foreach($dataRow as $cellValue) { + $rowXML .= $this->getCellXML($rowIndex, $cellNumber, $cellValue, $style->getId()); + $cellNumber++; + } + + $rowXML .= ''; + + $wasWriteSuccessful = fwrite($this->sheetFilePointer, $rowXML); + if ($wasWriteSuccessful === false) { + throw new IOException("Unable to write data in {$this->worksheetFilePath}"); + } + } + + /** + * Build and return xml for a single cell. + * + * @param int $rowIndex + * @param int $cellNumber + * @param mixed $cellValue + * @param int $styleId + * @return string + * @throws InvalidArgumentException If the given value cannot be processed + */ + protected function getCellXML($rowIndex, $cellNumber, $cellValue, $styleId) + { + $columnIndex = CellHelper::getCellIndexFromColumnIndex($cellNumber); + $cellXML = 'getCellXMLFragmentForNonEmptyString($cellValue); + } else if (CellHelper::isBoolean($cellValue)) { + $cellXML .= ' t="b">' . intval($cellValue) . ''; + } else if (CellHelper::isNumeric($cellValue)) { + $cellXML .= '>' . $cellValue . ''; + } else if (empty($cellValue)) { + if ($this->styleHelper->shouldApplyStyleOnEmptyCell($styleId)) { + $cellXML .= '/>'; + } else { + // don't write empty cells that do no need styling + // NOTE: not appending to $cellXML is the right behavior!! + $cellXML = ''; + } + } else { + throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cellValue)); + } + + return $cellXML; + } + + /** + * Returns the XML fragment for a cell containing a non empty string + * + * @param string $cellValue The cell value + * @return string The XML fragment representing the cell + * @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell + */ + protected function getCellXMLFragmentForNonEmptyString($cellValue) + { + if ($this->stringHelper->getStringLength($cellValue) > self::MAX_CHARACTERS_PER_CELL) { + throw new InvalidArgumentException('Trying to add a value that exceeds the maximum number of characters allowed in a cell (32,767)'); + } + + if ($this->shouldUseInlineStrings) { + $cellXMLFragment = ' t="inlineStr">' . $this->stringsEscaper->escape($cellValue) . ''; + } else { + $sharedStringId = $this->sharedStringsHelper->writeString($cellValue); + $cellXMLFragment = ' t="s">' . $sharedStringId . ''; + } + + return $cellXMLFragment; + } + + /** + * Closes the worksheet + * + * @return void + */ + public function close() + { + if (!is_resource($this->sheetFilePointer)) { + return; + } + + fwrite($this->sheetFilePointer, ''); + fwrite($this->sheetFilePointer, ''); + fclose($this->sheetFilePointer); + } +} diff --git a/lib/vendor/box/spout/src/Spout/Writer/XLSX/Writer.php b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Writer.php new file mode 100644 index 0000000000..965955a384 --- /dev/null +++ b/lib/vendor/box/spout/src/Spout/Writer/XLSX/Writer.php @@ -0,0 +1,132 @@ +throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->tempFolder = $tempFolder; + return $this; + } + + /** + * Use inline string to be more memory efficient. If set to false, it will use shared strings. + * This must be set before opening the writer. + * + * @api + * @param bool $shouldUseInlineStrings Whether inline or shared strings should be used + * @return Writer + * @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened + */ + public function setShouldUseInlineStrings($shouldUseInlineStrings) + { + $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.'); + + $this->shouldUseInlineStrings = $shouldUseInlineStrings; + return $this; + } + + /** + * Configures the write and sets the current sheet pointer to a new sheet. + * + * @return void + * @throws \Box\Spout\Common\Exception\IOException If unable to open the file for writing + */ + protected function openWriter() + { + if (!$this->book) { + $tempFolder = ($this->tempFolder) ? : sys_get_temp_dir(); + $this->book = new Workbook($tempFolder, $this->shouldUseInlineStrings, $this->shouldCreateNewSheetsAutomatically, $this->defaultRowStyle); + $this->book->addNewSheetAndMakeItCurrent(); + } + } + + /** + * @return Internal\Workbook The workbook representing the file to be written + */ + protected function getWorkbook() + { + return $this->book; + } + + /** + * Adds data to the currently opened writer. + * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination + * with the creation of new worksheets if one worksheet has reached its maximum capicity. + * + * @param array $dataRow Array containing data to be written. + * Example $dataRow = ['data1', 1234, null, '', 'data5']; + * @param \Box\Spout\Writer\Style\Style $style Style to be applied to the row. + * @return void + * @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet + * @throws \Box\Spout\Common\Exception\IOException If unable to write data + */ + protected function addRowToWriter(array $dataRow, $style) + { + $this->throwIfBookIsNotAvailable(); + $this->book->addRowToCurrentWorksheet($dataRow, $style); + } + + /** + * Returns the default style to be applied to rows. + * + * @return \Box\Spout\Writer\Style\Style + */ + protected function getDefaultRowStyle() + { + return (new StyleBuilder()) + ->setFontSize(self::DEFAULT_FONT_SIZE) + ->setFontName(self::DEFAULT_FONT_NAME) + ->build(); + } + + /** + * Closes the writer, preventing any additional writing. + * + * @return void + */ + protected function closeWriter() + { + if ($this->book) { + $this->book->close($this->filePointer); + } + } +} diff --git a/lib/vendor/composer/ClassLoader.php b/lib/vendor/composer/ClassLoader.php new file mode 100644 index 0000000000..afef3fa2ad --- /dev/null +++ b/lib/vendor/composer/ClassLoader.php @@ -0,0 +1,572 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var ?string */ + private $vendorDir; + + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ + private $missingClasses = array(); + + /** @var ?string */ + private $apcuPrefix; + + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array[] + * @psalm-return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return string[] Array of classname => path + * @psalm-return array + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/lib/vendor/composer/InstalledVersions.php b/lib/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000000..948bb4098b --- /dev/null +++ b/lib/vendor/composer/InstalledVersions.php @@ -0,0 +1,360 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + $copiedLocalDir = false; + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $required; + $copiedLocalDir = true; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array() && !$copiedLocalDir) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/lib/vendor/composer/LICENSE b/lib/vendor/composer/LICENSE new file mode 100644 index 0000000000..f27399a042 --- /dev/null +++ b/lib/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/lib/vendor/composer/autoload_classmap.php b/lib/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000000..9bfd96643c --- /dev/null +++ b/lib/vendor/composer/autoload_classmap.php @@ -0,0 +1,13 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php', + 'PclZip' => $vendorDir . '/pclzip/pclzip/pclzip.lib.php', + 'Requests' => $vendorDir . '/rmccue/requests/library/Requests.php', +); diff --git a/lib/vendor/composer/autoload_files.php b/lib/vendor/composer/autoload_files.php new file mode 100644 index 0000000000..e4c5145101 --- /dev/null +++ b/lib/vendor/composer/autoload_files.php @@ -0,0 +1,73 @@ + $vendorDir . '/laminas/laminas-zendframework-bridge/src/autoload.php', + 'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php', + '21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php', + '1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php', + 'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php', + '4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php', + 'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php', + '02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php', + '88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php', + '60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php', + '13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php', + '838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php', + 'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php', + '9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php', + '36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php', + '05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php', + 'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php', + '141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php', + 'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php', + '01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php', + '803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php', + '3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php', + '77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php', + '4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php', + 'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php', + 'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php', + '6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php', + '4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php', + 'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php', + '383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php', + '150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php', + '549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php', + '6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php', + '22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php', + 'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php', + 'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php', + '2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php', + '24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php', + 'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php', + '47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php', + '883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php', + 'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php', + 'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php', + '3af723442581d6c310bf44543f9f5c60' => $vendorDir . '/markbaker/matrix/classes/src/Functions/adjoint.php', + 'd803221834c8b57fec95debb5406a797' => $vendorDir . '/markbaker/matrix/classes/src/Functions/antidiagonal.php', + '4714cafbd3be4c72c274a25eae9396bb' => $vendorDir . '/markbaker/matrix/classes/src/Functions/cofactors.php', + '89719dc7c77436609d1c1c31f0797b8f' => $vendorDir . '/markbaker/matrix/classes/src/Functions/determinant.php', + 'c28af79ec7730859d83f2d4310b8dd0b' => $vendorDir . '/markbaker/matrix/classes/src/Functions/diagonal.php', + 'c5d82bf1ac485e445f911e55789ab4e6' => $vendorDir . '/markbaker/matrix/classes/src/Functions/identity.php', + '0d2d594de24a247f7a33499e933aa21e' => $vendorDir . '/markbaker/matrix/classes/src/Functions/inverse.php', + 'f37c25880804a014ef40c8bffbab1b10' => $vendorDir . '/markbaker/matrix/classes/src/Functions/minors.php', + 'd6e4e42171df0dbea253b3067fefda38' => $vendorDir . '/markbaker/matrix/classes/src/Functions/trace.php', + '2c9b19fa954fd3e6fcc7e7a1383caddd' => $vendorDir . '/markbaker/matrix/classes/src/Functions/transpose.php', + '0a538fc9b897450ec362480ebbebe94f' => $vendorDir . '/markbaker/matrix/classes/src/Operations/add.php', + 'f0843f7f4089ec2343c7445544356385' => $vendorDir . '/markbaker/matrix/classes/src/Operations/directsum.php', + 'ad3e8c29aa16d134661a414265677b61' => $vendorDir . '/markbaker/matrix/classes/src/Operations/subtract.php', + '8d37dad4703fab45bfec9dd0bbf3278e' => $vendorDir . '/markbaker/matrix/classes/src/Operations/multiply.php', + '4888a6f58c08148ebe17682f9ce9b2a8' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideby.php', + 'eef6fa3879d3efa347cd24d5eb348f85' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideinto.php', + '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + '04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php', + 'dc1275c308c5b416beb314b6317daca2' => $vendorDir . '/overtrue/pinyin/src/const.php', + 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', + '941748b3c8cae4466c827dfb5ca9602a' => $vendorDir . '/rmccue/requests/library/Deprecated.php', +); diff --git a/lib/vendor/composer/autoload_namespaces.php b/lib/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000000..58307f00f5 --- /dev/null +++ b/lib/vendor/composer/autoload_namespaces.php @@ -0,0 +1,14 @@ + array($vendorDir . '/erusev/parsedown'), + 'PHPThumb\\Tests' => array($vendorDir . '/masterexploder/phpthumb/tests'), + 'PHPThumb' => array($vendorDir . '/masterexploder/phpthumb/src'), + 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), + 'Detection' => array($vendorDir . '/mobiledetect/mobiledetectlib/namespaced'), +); diff --git a/lib/vendor/composer/autoload_psr4.php b/lib/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000000..1f75ac97b2 --- /dev/null +++ b/lib/vendor/composer/autoload_psr4.php @@ -0,0 +1,26 @@ + array($vendorDir . '/phpseclib/phpseclib/phpseclib'), + 'WpOrg\\Requests\\' => array($vendorDir . '/rmccue/requests/src'), + 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'PhpOffice\\PhpWord\\' => array($vendorDir . '/phpoffice/phpword/src/PhpWord'), + 'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'), + 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), + 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), + 'Overtrue\\Pinyin\\' => array($vendorDir . '/overtrue/pinyin/src'), + 'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'), + 'Laminas\\ZendFrameworkBridge\\' => array($vendorDir . '/laminas/laminas-zendframework-bridge/src'), + 'Laminas\\Escaper\\' => array($vendorDir . '/laminas/laminas-escaper/src'), + 'Gregwar\\' => array($vendorDir . '/gregwar/captcha/src/Gregwar'), + 'GorHill\\FineDiff\\' => array($vendorDir . '/gorhill/php-fine-diff/GorHill/FineDiff'), + 'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'), + 'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'), + 'Box\\Spout\\' => array($vendorDir . '/box/spout/src/Spout'), +); diff --git a/lib/vendor/composer/autoload_real.php b/lib/vendor/composer/autoload_real.php new file mode 100644 index 0000000000..362686ce20 --- /dev/null +++ b/lib/vendor/composer/autoload_real.php @@ -0,0 +1,80 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequireafe523bf1918581efcc4a020da6c4d4e($fileIdentifier, $file); + } + + return $loader; + } +} + +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ +function composerRequireafe523bf1918581efcc4a020da6c4d4e($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } +} diff --git a/lib/vendor/composer/autoload_static.php b/lib/vendor/composer/autoload_static.php new file mode 100644 index 0000000000..d67255451c --- /dev/null +++ b/lib/vendor/composer/autoload_static.php @@ -0,0 +1,246 @@ + __DIR__ . '/..' . '/laminas/laminas-zendframework-bridge/src/autoload.php', + 'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php', + '21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php', + '1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php', + 'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php', + '4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php', + 'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php', + '02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php', + '88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php', + '60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php', + '13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php', + '838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php', + 'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php', + '9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php', + '36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php', + '05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php', + 'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php', + '141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php', + 'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php', + '01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php', + '803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php', + '3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php', + '77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php', + '4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php', + 'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php', + 'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php', + '6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php', + '4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php', + 'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php', + '383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php', + '150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php', + '549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php', + '6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php', + '22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php', + 'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php', + 'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php', + '2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php', + '24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php', + 'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php', + '47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php', + '883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php', + 'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php', + 'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php', + '3af723442581d6c310bf44543f9f5c60' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/adjoint.php', + 'd803221834c8b57fec95debb5406a797' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/antidiagonal.php', + '4714cafbd3be4c72c274a25eae9396bb' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/cofactors.php', + '89719dc7c77436609d1c1c31f0797b8f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/determinant.php', + 'c28af79ec7730859d83f2d4310b8dd0b' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/diagonal.php', + 'c5d82bf1ac485e445f911e55789ab4e6' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/identity.php', + '0d2d594de24a247f7a33499e933aa21e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/inverse.php', + 'f37c25880804a014ef40c8bffbab1b10' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/minors.php', + 'd6e4e42171df0dbea253b3067fefda38' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/trace.php', + '2c9b19fa954fd3e6fcc7e7a1383caddd' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/transpose.php', + '0a538fc9b897450ec362480ebbebe94f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/add.php', + 'f0843f7f4089ec2343c7445544356385' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/directsum.php', + 'ad3e8c29aa16d134661a414265677b61' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/subtract.php', + '8d37dad4703fab45bfec9dd0bbf3278e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/multiply.php', + '4888a6f58c08148ebe17682f9ce9b2a8' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideby.php', + 'eef6fa3879d3efa347cd24d5eb348f85' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideinto.php', + '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + '04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php', + 'dc1275c308c5b416beb314b6317daca2' => __DIR__ . '/..' . '/overtrue/pinyin/src/const.php', + 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', + '941748b3c8cae4466c827dfb5ca9602a' => __DIR__ . '/..' . '/rmccue/requests/library/Deprecated.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'p' => + array ( + 'phpseclib3\\' => 11, + ), + 'W' => + array ( + 'WpOrg\\Requests\\' => 15, + ), + 'S' => + array ( + 'Symfony\\Component\\Finder\\' => 25, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'PhpOffice\\PhpWord\\' => 18, + 'PhpOffice\\PhpSpreadsheet\\' => 25, + 'ParagonIE\\ConstantTime\\' => 23, + 'PHPMailer\\PHPMailer\\' => 20, + ), + 'O' => + array ( + 'Overtrue\\Pinyin\\' => 16, + ), + 'M' => + array ( + 'Matrix\\' => 7, + ), + 'L' => + array ( + 'Laminas\\ZendFrameworkBridge\\' => 28, + 'Laminas\\Escaper\\' => 16, + ), + 'G' => + array ( + 'Gregwar\\' => 8, + 'GorHill\\FineDiff\\' => 17, + ), + 'C' => + array ( + 'Cron\\' => 5, + 'Complex\\' => 8, + ), + 'B' => + array ( + 'Box\\Spout\\' => 10, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'phpseclib3\\' => + array ( + 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', + ), + 'WpOrg\\Requests\\' => + array ( + 0 => __DIR__ . '/..' . '/rmccue/requests/src', + ), + 'Symfony\\Component\\Finder\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/finder', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'PhpOffice\\PhpWord\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoffice/phpword/src/PhpWord', + ), + 'PhpOffice\\PhpSpreadsheet\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet', + ), + 'ParagonIE\\ConstantTime\\' => + array ( + 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', + ), + 'PHPMailer\\PHPMailer\\' => + array ( + 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', + ), + 'Overtrue\\Pinyin\\' => + array ( + 0 => __DIR__ . '/..' . '/overtrue/pinyin/src', + ), + 'Matrix\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src', + ), + 'Laminas\\ZendFrameworkBridge\\' => + array ( + 0 => __DIR__ . '/..' . '/laminas/laminas-zendframework-bridge/src', + ), + 'Laminas\\Escaper\\' => + array ( + 0 => __DIR__ . '/..' . '/laminas/laminas-escaper/src', + ), + 'Gregwar\\' => + array ( + 0 => __DIR__ . '/..' . '/gregwar/captcha/src/Gregwar', + ), + 'GorHill\\FineDiff\\' => + array ( + 0 => __DIR__ . '/..' . '/gorhill/php-fine-diff/GorHill/FineDiff', + ), + 'Cron\\' => + array ( + 0 => __DIR__ . '/..' . '/dragonmantank/cron-expression/src/Cron', + ), + 'Complex\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/complex/classes/src', + ), + 'Box\\Spout\\' => + array ( + 0 => __DIR__ . '/..' . '/box/spout/src/Spout', + ), + ); + + public static $prefixesPsr0 = array ( + 'P' => + array ( + 'Parsedown' => + array ( + 0 => __DIR__ . '/..' . '/erusev/parsedown', + ), + 'PHPThumb\\Tests' => + array ( + 0 => __DIR__ . '/..' . '/masterexploder/phpthumb/tests', + ), + 'PHPThumb' => + array ( + 0 => __DIR__ . '/..' . '/masterexploder/phpthumb/src', + ), + ), + 'H' => + array ( + 'HTMLPurifier' => + array ( + 0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library', + ), + ), + 'D' => + array ( + 'Detection' => + array ( + 0 => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced', + ), + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Mobile_Detect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/Mobile_Detect.php', + 'PclZip' => __DIR__ . '/..' . '/pclzip/pclzip/pclzip.lib.php', + 'Requests' => __DIR__ . '/..' . '/rmccue/requests/library/Requests.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::$prefixesPsr0; + $loader->classMap = ComposerStaticInitafe523bf1918581efcc4a020da6c4d4e::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/lib/vendor/composer/installed.json b/lib/vendor/composer/installed.json new file mode 100644 index 0000000000..52a2ae0441 --- /dev/null +++ b/lib/vendor/composer/installed.json @@ -0,0 +1,1698 @@ +{ + "packages": [ + { + "name": "box/spout", + "version": "v2.7.3", + "version_normalized": "2.7.3.0", + "source": { + "type": "git", + "url": "https://github.com/box/spout.git", + "reference": "3681a3421a868ab9a65da156c554f756541f452b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/box/spout/zipball/3681a3421a868ab9a65da156c554f756541f452b", + "reference": "3681a3421a868ab9a65da156c554f756541f452b", + "shasum": "" + }, + "require": { + "ext-xmlreader": "*", + "ext-zip": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.0" + }, + "suggest": { + "ext-iconv": "To handle non UTF-8 CSV files (if \"php-intl\" is not already installed or is too limited)", + "ext-intl": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)" + }, + "time": "2017-09-25T19:44:35+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Box\\Spout\\": "src/Spout" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Adrien Loison", + "email": "adrien@box.com" + } + ], + "description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way", + "homepage": "https://www.github.com/box/spout", + "keywords": [ + "OOXML", + "csv", + "excel", + "memory", + "odf", + "ods", + "office", + "open", + "php", + "read", + "scale", + "spreadsheet", + "stream", + "write", + "xlsx" + ], + "support": { + "issues": "https://github.com/box/spout/issues", + "source": "https://github.com/box/spout/tree/v2.7.3" + }, + "abandoned": true, + "install-path": "../box/spout" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v2.3.1", + "version_normalized": "2.3.1.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/65b2d8ee1f10915efb3b55597da3404f096acba2", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0|^8.0|^9.0" + }, + "time": "2020-10-13T00:52:37+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "install-path": "../dragonmantank/cron-expression" + }, + { + "name": "erusev/parsedown", + "version": "1.7.4", + "version_normalized": "1.7.4.0", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "time": "2019-12-30T22:54:17+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "install-path": "../erusev/parsedown" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.18.0", + "version_normalized": "4.18.0.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "time": "2024-11-01T03:51:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0" + }, + "install-path": "../ezyang/htmlpurifier" + }, + { + "name": "gorhill/php-fine-diff", + "version": "0.1.0", + "version_normalized": "0.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/falk-graeser/PHP-FineDiff.git", + "reference": "b0c9ab136958882c501d461b0ad204f908e19392" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/falk-graeser/PHP-FineDiff/zipball/b0c9ab136958882c501d461b0ad204f908e19392", + "reference": "b0c9ab136958882c501d461b0ad204f908e19392", + "shasum": "" + }, + "time": "2015-07-30T10:21:26+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "GorHill\\FineDiff\\": "GorHill/FineDiff" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raymond Hill", + "email": "r.michael@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "Developer" + }, + { + "name": "Falk Gräser", + "email": "f.graeser@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "The-Clean-Up-Guy" + } + ], + "homepage": "http://www.raymondhill.net/finediff/", + "keywords": [ + "finediff" + ], + "support": { + "source": "https://github.com/falk-graeser/PHP-FineDiff/tree/0.1.0" + }, + "install-path": "../gorhill/php-fine-diff" + }, + { + "name": "gregwar/captcha", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Captcha.git", + "reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4edbcd09fde4353b94ce550f43460eba73baf2cc", + "reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-mbstring": "*", + "php": ">=5.3.0", + "symfony/finder": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0" + }, + "time": "2025-06-23T12:25:54+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Gregwar\\": "src/Gregwar" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "description": "Captcha generator", + "homepage": "https://github.com/Gregwar/Captcha", + "keywords": [ + "bot", + "captcha", + "spam" + ], + "support": { + "issues": "https://github.com/Gregwar/Captcha/issues", + "source": "https://github.com/Gregwar/Captcha/tree/v1.3.0" + }, + "install-path": "../gregwar/captcha" + }, + { + "name": "laminas/laminas-escaper", + "version": "2.6.1", + "version_normalized": "2.6.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "25f2a053eadfa92ddacb609dcbbc39362610da70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/25f2a053eadfa92ddacb609dcbbc39362610da70", + "reference": "25f2a053eadfa92ddacb609dcbbc39362610da70", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^5.6 || ^7.0" + }, + "replace": { + "zendframework/zend-escaper": "self.version" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2" + }, + "time": "2019-12-31T16:43:30+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev", + "dev-develop": "2.7.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "install-path": "../laminas/laminas-escaper" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "time": "2020-09-14T14:23:00+00:00", + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": true, + "install-path": "../laminas/laminas-zendframework-bridge" + }, + { + "name": "markbaker/complex", + "version": "1.5.0", + "version_normalized": "1.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/c3131244e29c08d44fefb49e0dd35021e9e39dd2", + "reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2", + "shasum": "" + }, + "require": { + "php": "^5.6.0|^7.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0|^5.0|^6.0|^7.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0", + "sebastian/phpcpd": "2.*", + "squizlabs/php_codesniffer": "^3.4.0" + }, + "time": "2020-08-26T19:47:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ], + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/1.5.0" + }, + "install-path": "../markbaker/complex" + }, + { + "name": "markbaker/matrix", + "version": "1.2.3", + "version_normalized": "1.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/44bb1ab01811116f01fe216ab37d921dccc6c10d", + "reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d", + "shasum": "" + }, + "require": { + "php": "^5.6.0|^7.0.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "dev-master", + "phploc/phploc": "^4", + "phpmd/phpmd": "dev-master", + "phpunit/phpunit": "^5.7|^6.0|7.0", + "sebastian/phpcpd": "^3.0", + "squizlabs/php_codesniffer": "^3.0@dev" + }, + "time": "2021-01-26T14:36:01+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ], + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/1.2.3" + }, + "install-path": "../markbaker/matrix" + }, + { + "name": "masterexploder/phpthumb", + "version": "2.1", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/masterexploder/PHPThumb.git", + "reference": "01f6aa65aa3d136e175f67da2b4ea3e316770d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/masterexploder/PHPThumb/zipball/01f6aa65aa3d136e175f67da2b4ea3e316770d02", + "reference": "01f6aa65aa3d136e175f67da2b4ea3e316770d02", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2015-09-08T22:55:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "PHPThumb": "src", + "PHPThumb\\Tests": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jarrod Nettles", + "email": "jarrod.nettles@icloud.com" + }, + { + "name": "Ian Selby", + "email": "ian@gxdlabs.com" + } + ], + "description": "A library for manipulating images in PHP.", + "homepage": "https://github.com/masterexploder/PHPThumb", + "keywords": [ + "image", + "resize", + "rotate" + ], + "support": { + "issues": "https://github.com/masterexploder/PHPThumb/issues", + "source": "https://github.com/masterexploder/PHPThumb/tree/2.1" + }, + "install-path": "../masterexploder/phpthumb" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.45", + "version_normalized": "2.8.45.0", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36" + }, + "time": "2023-11-07T21:57:25+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Detection": "namespaced/" + }, + "classmap": [ + "Mobile_Detect.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.45" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "install-path": "../mobiledetect/mobiledetectlib" + }, + { + "name": "mustangostang/spyc", + "version": "0.6.3", + "version_normalized": "0.6.3.0", + "source": { + "type": "git", + "url": "https://github.com/mustangostang/spyc.git", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/4627c838b16550b666d15aeae1e5289dd5b77da0", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, + "time": "2019-09-10T13:16:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "Spyc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "mustangostang", + "email": "vlad.andersen@gmail.com" + } + ], + "description": "A simple YAML loader/dumper class for PHP", + "homepage": "https://github.com/mustangostang/spyc/", + "keywords": [ + "spyc", + "yaml", + "yml" + ], + "support": { + "issues": "https://github.com/mustangostang/spyc/issues", + "source": "https://github.com/mustangostang/spyc/tree/0.6.3" + }, + "install-path": "../mustangostang/spyc" + }, + { + "name": "overtrue/pinyin", + "version": "4.0.5", + "version_normalized": "4.0.5.0", + "source": { + "type": "git", + "url": "https://github.com/overtrue/pinyin.git", + "reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/overtrue/pinyin/zipball/94fdb3ea6eca5677afd9548111d95bedcd5a4086", + "reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.5" + }, + "time": "2019-09-20T12:43:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/const.php" + ], + "psr-4": { + "Overtrue\\Pinyin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carlos", + "homepage": "http://github.com/overtrue" + } + ], + "description": "Chinese to pinyin translator.", + "homepage": "https://github.com/overtrue/pinyin", + "keywords": [ + "Chinese", + "Pinyin", + "cn2pinyin" + ], + "support": { + "issues": "https://github.com/overtrue/pinyin/issues", + "source": "https://github.com/overtrue/pinyin/tree/master" + }, + "install-path": "../overtrue/pinyin" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.7.0", + "version_normalized": "2.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "time": "2024-05-08T12:18:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "install-path": "../paragonie/constant_time_encoding" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "version_normalized": "9.99.100.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2020-10-15T08:29:30+00:00", + "type": "library", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "install-path": "../paragonie/random_compat" + }, + { + "name": "pclzip/pclzip", + "version": "2.8.2", + "version_normalized": "2.8.2.0", + "source": { + "type": "git", + "url": "https://github.com/ivanlanin/pclzip.git", + "reference": "19dd1de9d3f5fc4d7d70175b4c344dee329f45fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ivanlanin/pclzip/zipball/19dd1de9d3f5fc4d7d70175b4c344dee329f45fd", + "reference": "19dd1de9d3f5fc4d7d70175b4c344dee329f45fd", + "shasum": "" + }, + "time": "2014-06-05T11:42:24+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "pclzip.lib.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Vincent Blavet" + } + ], + "description": "A PHP library that offers compression and extraction functions for Zip formatted archives", + "homepage": "http://www.phpconcept.net/pclzip", + "keywords": [ + "php", + "zip" + ], + "support": { + "issues": "https://github.com/ivanlanin/pclzip/issues", + "source": "https://github.com/ivanlanin/pclzip/tree/master" + }, + "install-path": "../pclzip/pclzip" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.10.0", + "version_normalized": "6.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.2", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "time": "2025-04-24T15:19:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "install-path": "../phpmailer/phpmailer" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.8.2", + "version_normalized": "1.8.2.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "0c1346a1956347590b7db09533966307d20cb7cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/0c1346a1956347590b7db09533966307d20cb7cc", + "reference": "0c1346a1956347590b7db09533966307d20cb7cc", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "markbaker/complex": "^1.4", + "markbaker/matrix": "^1.1", + "php": "^5.6|^7.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "^1.0.0", + "dompdf/dompdf": "^0.8.0", + "friendsofphp/php-cs-fixer": "@stable", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^7.0.0", + "phpcompatibility/php-compatibility": "^8.0", + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.3", + "tecnickcom/tcpdf": "^6.2" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "time": "2019-07-08T21:21:25+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + }, + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.8.2" + }, + "install-path": "../phpoffice/phpspreadsheet" + }, + { + "name": "phpoffice/phpword", + "version": "0.18.3", + "version_normalized": "0.18.3.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PHPWord.git", + "reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/be0190cd5d8f95b4be08d5853b107aa4e352759a", + "reference": "be0190cd5d8f95b4be08d5853b107aa4e352759a", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "laminas/laminas-escaper": "^2.2", + "php": "^5.3.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "dompdf/dompdf": "0.8.* || 1.0.*", + "ext-gd": "*", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^2.2", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", + "php-coveralls/php-coveralls": "1.1.0 || ^2.0", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^4.8.36 || ^7.0", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", + "tecnickcom/tcpdf": "6.*" + }, + "suggest": { + "dompdf/dompdf": "Allows writing PDF", + "ext-gd2": "Allows adding images", + "ext-xmlwriter": "Allows writing OOXML and ODF", + "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", + "ext-zip": "Allows writing OOXML and ODF" + }, + "time": "2022-02-17T15:40:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.19-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOffice\\PhpWord\\": "src/PhpWord" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Mark Baker" + }, + { + "name": "Gabriel Bull", + "email": "me@gabrielbull.com", + "homepage": "http://gabrielbull.com/" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net/blog/" + }, + { + "name": "Ivan Lanin", + "homepage": "http://ivan.lanin.org" + }, + { + "name": "Roman Syroeshko", + "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" + }, + { + "name": "Antoine de Troostembergh" + } + ], + "description": "PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)", + "homepage": "http://phpoffice.github.io", + "keywords": [ + "ISO IEC 29500", + "OOXML", + "Office Open XML", + "OpenDocument", + "OpenXML", + "PhpOffice", + "PhpWord", + "Rich Text Format", + "WordprocessingML", + "doc", + "docx", + "html", + "odf", + "odt", + "office", + "pdf", + "php", + "reader", + "rtf", + "template", + "template processor", + "word", + "writer" + ], + "support": { + "issues": "https://github.com/PHPOffice/PHPWord/issues", + "source": "https://github.com/PHPOffice/PHPWord/tree/0.18.3" + }, + "install-path": "../phpoffice/phpword" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.46", + "version_normalized": "3.0.46.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "time": "2025-06-26T16:29:55+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "install-path": "../phpseclib/phpseclib" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-10-23T01:57:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "rmccue/requests", + "version": "v2.0.15", + "version_normalized": "2.0.15.0", + "source": { + "type": "git", + "url": "https://github.com/WordPress/Requests.git", + "reference": "877cd66169755899682f1595e057334b40d9d149" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/877cd66169755899682f1595e057334b40d9d149", + "reference": "877cd66169755899682f1595e057334b40d9d149", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "php-parallel-lint/php-console-highlighter": "^0.5.0", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "requests/test-server": "dev-main", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6", + "wp-coding-standards/wpcs": "^2.0", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", + "ext-curl": "For improved performance", + "ext-openssl": "For secure transport support", + "ext-zlib": "For improved performance when decompressing encoded streams" + }, + "time": "2025-01-21T10:13:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "library/Deprecated.php" + ], + "psr-4": { + "WpOrg\\Requests\\": "src/" + }, + "classmap": [ + "library/Requests.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Ryan McCue", + "homepage": "https://rmccue.io/" + }, + { + "name": "Alain Schlesser", + "homepage": "https://github.com/schlessera" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl" + }, + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/Requests/graphs/contributors" + } + ], + "description": "A HTTP library written in PHP, for human beings.", + "homepage": "https://requests.ryanmccue.info/", + "keywords": [ + "curl", + "fsockopen", + "http", + "idna", + "ipv6", + "iri", + "sockets" + ], + "support": { + "docs": "https://requests.ryanmccue.info/", + "issues": "https://github.com/WordPress/Requests/issues", + "source": "https://github.com/WordPress/Requests" + }, + "install-path": "../rmccue/requests" + }, + { + "name": "symfony/finder", + "version": "v3.4.47", + "version_normalized": "3.4.47.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "time": "2020-11-16T17:02:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/finder" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/lib/vendor/composer/installed.php b/lib/vendor/composer/installed.php new file mode 100644 index 0000000000..a554ceaf93 --- /dev/null +++ b/lib/vendor/composer/installed.php @@ -0,0 +1,245 @@ + array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '14f290ae63a7ce26371b9598aeb5517f537e61c7', + 'name' => '__root__', + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => '14f290ae63a7ce26371b9598aeb5517f537e61c7', + 'dev_requirement' => false, + ), + 'box/spout' => array( + 'pretty_version' => 'v2.7.3', + 'version' => '2.7.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../box/spout', + 'aliases' => array(), + 'reference' => '3681a3421a868ab9a65da156c554f756541f452b', + 'dev_requirement' => false, + ), + 'dragonmantank/cron-expression' => array( + 'pretty_version' => 'v2.3.1', + 'version' => '2.3.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../dragonmantank/cron-expression', + 'aliases' => array(), + 'reference' => '65b2d8ee1f10915efb3b55597da3404f096acba2', + 'dev_requirement' => false, + ), + 'erusev/parsedown' => array( + 'pretty_version' => '1.7.4', + 'version' => '1.7.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../erusev/parsedown', + 'aliases' => array(), + 'reference' => 'cb17b6477dfff935958ba01325f2e8a2bfa6dab3', + 'dev_requirement' => false, + ), + 'ezyang/htmlpurifier' => array( + 'pretty_version' => 'v4.18.0', + 'version' => '4.18.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ezyang/htmlpurifier', + 'aliases' => array(), + 'reference' => 'cb56001e54359df7ae76dc522d08845dc741621b', + 'dev_requirement' => false, + ), + 'gorhill/php-fine-diff' => array( + 'pretty_version' => '0.1.0', + 'version' => '0.1.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../gorhill/php-fine-diff', + 'aliases' => array(), + 'reference' => 'b0c9ab136958882c501d461b0ad204f908e19392', + 'dev_requirement' => false, + ), + 'gregwar/captcha' => array( + 'pretty_version' => 'v1.3.0', + 'version' => '1.3.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../gregwar/captcha', + 'aliases' => array(), + 'reference' => '4edbcd09fde4353b94ce550f43460eba73baf2cc', + 'dev_requirement' => false, + ), + 'laminas/laminas-escaper' => array( + 'pretty_version' => '2.6.1', + 'version' => '2.6.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laminas/laminas-escaper', + 'aliases' => array(), + 'reference' => '25f2a053eadfa92ddacb609dcbbc39362610da70', + 'dev_requirement' => false, + ), + 'laminas/laminas-zendframework-bridge' => array( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laminas/laminas-zendframework-bridge', + 'aliases' => array(), + 'reference' => '6ede70583e101030bcace4dcddd648f760ddf642', + 'dev_requirement' => false, + ), + 'markbaker/complex' => array( + 'pretty_version' => '1.5.0', + 'version' => '1.5.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../markbaker/complex', + 'aliases' => array(), + 'reference' => 'c3131244e29c08d44fefb49e0dd35021e9e39dd2', + 'dev_requirement' => false, + ), + 'markbaker/matrix' => array( + 'pretty_version' => '1.2.3', + 'version' => '1.2.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../markbaker/matrix', + 'aliases' => array(), + 'reference' => '44bb1ab01811116f01fe216ab37d921dccc6c10d', + 'dev_requirement' => false, + ), + 'masterexploder/phpthumb' => array( + 'pretty_version' => '2.1', + 'version' => '2.1.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../masterexploder/phpthumb', + 'aliases' => array(), + 'reference' => '01f6aa65aa3d136e175f67da2b4ea3e316770d02', + 'dev_requirement' => false, + ), + 'mobiledetect/mobiledetectlib' => array( + 'pretty_version' => '2.8.45', + 'version' => '2.8.45.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mobiledetect/mobiledetectlib', + 'aliases' => array(), + 'reference' => '96aaebcf4f50d3d2692ab81d2c5132e425bca266', + 'dev_requirement' => false, + ), + 'mustangostang/spyc' => array( + 'pretty_version' => '0.6.3', + 'version' => '0.6.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mustangostang/spyc', + 'aliases' => array(), + 'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0', + 'dev_requirement' => false, + ), + 'overtrue/pinyin' => array( + 'pretty_version' => '4.0.5', + 'version' => '4.0.5.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../overtrue/pinyin', + 'aliases' => array(), + 'reference' => '94fdb3ea6eca5677afd9548111d95bedcd5a4086', + 'dev_requirement' => false, + ), + 'paragonie/constant_time_encoding' => array( + 'pretty_version' => 'v2.7.0', + 'version' => '2.7.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding', + 'aliases' => array(), + 'reference' => '52a0d99e69f56b9ec27ace92ba56897fe6993105', + 'dev_requirement' => false, + ), + 'paragonie/random_compat' => array( + 'pretty_version' => 'v9.99.100', + 'version' => '9.99.100.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/random_compat', + 'aliases' => array(), + 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a', + 'dev_requirement' => false, + ), + 'pclzip/pclzip' => array( + 'pretty_version' => '2.8.2', + 'version' => '2.8.2.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pclzip/pclzip', + 'aliases' => array(), + 'reference' => '19dd1de9d3f5fc4d7d70175b4c344dee329f45fd', + 'dev_requirement' => false, + ), + 'phpmailer/phpmailer' => array( + 'pretty_version' => 'v6.10.0', + 'version' => '6.10.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpmailer/phpmailer', + 'aliases' => array(), + 'reference' => 'bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144', + 'dev_requirement' => false, + ), + 'phpoffice/phpspreadsheet' => array( + 'pretty_version' => '1.8.2', + 'version' => '1.8.2.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet', + 'aliases' => array(), + 'reference' => '0c1346a1956347590b7db09533966307d20cb7cc', + 'dev_requirement' => false, + ), + 'phpoffice/phpword' => array( + 'pretty_version' => '0.18.3', + 'version' => '0.18.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpoffice/phpword', + 'aliases' => array(), + 'reference' => 'be0190cd5d8f95b4be08d5853b107aa4e352759a', + 'dev_requirement' => false, + ), + 'phpseclib/phpseclib' => array( + 'pretty_version' => '3.0.46', + 'version' => '3.0.46.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpseclib/phpseclib', + 'aliases' => array(), + 'reference' => '56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6', + 'dev_requirement' => false, + ), + 'psr/simple-cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + 'dev_requirement' => false, + ), + 'rmccue/requests' => array( + 'pretty_version' => 'v2.0.15', + 'version' => '2.0.15.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rmccue/requests', + 'aliases' => array(), + 'reference' => '877cd66169755899682f1595e057334b40d9d149', + 'dev_requirement' => false, + ), + 'symfony/finder' => array( + 'pretty_version' => 'v3.4.47', + 'version' => '3.4.47.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/finder', + 'aliases' => array(), + 'reference' => 'b6b6ad3db3edb1b4b1c1896b1975fb684994de6e', + 'dev_requirement' => false, + ), + 'zendframework/zend-escaper' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '2.6.1', + ), + ), + ), +); diff --git a/lib/vendor/composer/platform_check.php b/lib/vendor/composer/platform_check.php new file mode 100644 index 0000000000..f79e574be7 --- /dev/null +++ b/lib/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/lib/vendor/dragonmantank/cron-expression/CHANGELOG.md b/lib/vendor/dragonmantank/cron-expression/CHANGELOG.md new file mode 100644 index 0000000000..4e207aaddb --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/CHANGELOG.md @@ -0,0 +1,84 @@ +# Change Log + +## [2.3.1] - 2020-10-12 +### Added +- Added support for PHP 8 (#92) +### Changed +- N/A +### Fixed +- N/A + +## [2.3.0] - 2019-03-30 +### Added +- Added support for DateTimeImmutable via DateTimeInterface +- Added support for PHP 7.3 +- Started listing projects that use the library +### Changed +- Errors should now report a human readable position in the cron expression, instead of starting at 0 +### Fixed +- N/A + +## [2.2.0] - 2018-06-05 +### Added +- Added support for steps larger than field ranges (#6) +## Changed +- N/A +### Fixed +- Fixed validation for numbers with leading 0s (#12) + +## [2.1.0] - 2018-04-06 +### Added +- N/A +### Changed +- Upgraded to PHPUnit 6 (#2) +### Fixed +- Refactored timezones to deal with some inconsistent behavior (#3) +- Allow ranges and lists in same expression (#5) +- Fixed regression where literals were not converted to their numerical counterpart (#) + +## [2.0.0] - 2017-10-12 +### Added +- N/A + +### Changed +- Dropped support for PHP 5.x +- Dropped support for the YEAR field, as it was not part of the cron standard + +### Fixed +- Reworked validation for all the field types +- Stepping should now work for 1-indexed fields like Month (#153) + +## [1.2.0] - 2017-01-22 +### Added +- Added IDE, CodeSniffer, and StyleCI.IO support + +### Changed +- Switched to PSR-4 Autoloading + +### Fixed +- 0 step expressions are handled better +- Fixed `DayOfMonth` validation to be more strict +- Typos + +## [1.1.0] - 2016-01-26 +### Added +- Support for non-hourly offset timezones +- Checks for valid expressions + +### Changed +- Max Iterations no longer hardcoded for `getRunDate()` +- Supports DateTimeImmutable for newer PHP verions + +### Fixed +- Fixed looping bug for PHP 7 when determining the last specified weekday of a month + +## [1.0.3] - 2013-11-23 +### Added +- Now supports expressions with any number of extra spaces, tabs, or newlines + +### Changed +- Using static instead of self in `CronExpression::factory` + +### Fixed +- Fixes issue [#28](https://github.com/mtdowling/cron-expression/issues/28) where PHP increments of ranges were failing due to PHP casting hyphens to 0 +- Only set default timezone if the given $currentTime is not a DateTime instance ([#34](https://github.com/mtdowling/cron-expression/issues/34)) diff --git a/lib/vendor/dragonmantank/cron-expression/LICENSE b/lib/vendor/dragonmantank/cron-expression/LICENSE new file mode 100644 index 0000000000..3e38bbc88d --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Michael Dowling , 2016 Chris Tankersley , and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lib/vendor/dragonmantank/cron-expression/README.md b/lib/vendor/dragonmantank/cron-expression/README.md new file mode 100644 index 0000000000..8e8021b2a1 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/README.md @@ -0,0 +1,78 @@ +PHP Cron Expression Parser +========================== + +[![Latest Stable Version](https://poser.pugx.org/dragonmantank/cron-expression/v/stable.png)](https://packagist.org/packages/dragonmantank/cron-expression) [![Total Downloads](https://poser.pugx.org/dragonmantank/cron-expression/downloads.png)](https://packagist.org/packages/dragonmantank/cron-expression) [![Build Status](https://secure.travis-ci.org/dragonmantank/cron-expression.png)](http://travis-ci.org/dragonmantank/cron-expression) + +The PHP cron expression parser can parse a CRON expression, determine if it is +due to run, calculate the next run date of the expression, and calculate the previous +run date of the expression. You can calculate dates far into the future or past by +skipping **n** number of matching dates. + +The parser can handle increments of ranges (e.g. */12, 2-59/3), intervals (e.g. 0-9), +lists (e.g. 1,2,3), **W** to find the nearest weekday for a given day of the month, **L** to +find the last day of the month, **L** to find the last given weekday of a month, and hash +(#) to find the nth weekday of a given month. + +More information about this fork can be found in the blog post [here](http://ctankersley.com/2017/10/12/cron-expression-update/). tl;dr - v2.0.0 is a major breaking change, and @dragonmantank can better take care of the project in a separate fork. + +Installing +========== + +Add the dependency to your project: + +```bash +composer require dragonmantank/cron-expression +``` + +Usage +===== +```php +isDue(); +echo $cron->getNextRunDate()->format('Y-m-d H:i:s'); +echo $cron->getPreviousRunDate()->format('Y-m-d H:i:s'); + +// Works with complex expressions +$cron = Cron\CronExpression::factory('3-59/15 6-12 */15 1 2-5'); +echo $cron->getNextRunDate()->format('Y-m-d H:i:s'); + +// Calculate a run date two iterations into the future +$cron = Cron\CronExpression::factory('@daily'); +echo $cron->getNextRunDate(null, 2)->format('Y-m-d H:i:s'); + +// Calculate a run date relative to a specific time +$cron = Cron\CronExpression::factory('@monthly'); +echo $cron->getNextRunDate('2010-01-12 00:00:00')->format('Y-m-d H:i:s'); +``` + +CRON Expressions +================ + +A CRON expression is a string representing the schedule for a particular command to execute. The parts of a CRON schedule are as follows: + + * * * * * + - - - - - + | | | | | + | | | | | + | | | | +----- day of week (0 - 7) (Sunday=0 or 7) + | | | +---------- month (1 - 12) + | | +--------------- day of month (1 - 31) + | +-------------------- hour (0 - 23) + +------------------------- min (0 - 59) + +Requirements +============ + +- PHP 7.0+ +- PHPUnit is required to run the unit tests +- Composer is required to run the unit tests + +Projects that Use cron-expression +================================= +* Part of the [Laravel Framework](https://github.com/laravel/framework/) +* Available as a [Symfony Bundle - setono/cron-expression-bundle](https://github.com/Setono/CronExpressionBundle) \ No newline at end of file diff --git a/lib/vendor/dragonmantank/cron-expression/composer.json b/lib/vendor/dragonmantank/cron-expression/composer.json new file mode 100644 index 0000000000..6fcf8184cd --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/composer.json @@ -0,0 +1,40 @@ +{ + "name": "dragonmantank/cron-expression", + "type": "library", + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": ["cron", "schedule"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0|^8.0|^9.0" + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/Cron/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php new file mode 100644 index 0000000000..8b1072ab2c --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php @@ -0,0 +1,286 @@ +fullRange = range($this->rangeStart, $this->rangeEnd); + } + + /** + * Check to see if a field is satisfied by a value + * + * @param string $dateValue Date value to check + * @param string $value Value to test + * + * @return bool + */ + public function isSatisfied($dateValue, $value) + { + if ($this->isIncrementsOfRanges($value)) { + return $this->isInIncrementsOfRanges($dateValue, $value); + } elseif ($this->isRange($value)) { + return $this->isInRange($dateValue, $value); + } + + return $value == '*' || $dateValue == $value; + } + + /** + * Check if a value is a range + * + * @param string $value Value to test + * + * @return bool + */ + public function isRange($value) + { + return strpos($value, '-') !== false; + } + + /** + * Check if a value is an increments of ranges + * + * @param string $value Value to test + * + * @return bool + */ + public function isIncrementsOfRanges($value) + { + return strpos($value, '/') !== false; + } + + /** + * Test if a value is within a range + * + * @param string $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInRange($dateValue, $value) + { + $parts = array_map(function($value) { + $value = trim($value); + $value = $this->convertLiterals($value); + return $value; + }, + explode('-', $value, 2) + ); + + + return $dateValue >= $parts[0] && $dateValue <= $parts[1]; + } + + /** + * Test if a value is within an increments of ranges (offset[-to]/step size) + * + * @param string $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInIncrementsOfRanges($dateValue, $value) + { + $chunks = array_map('trim', explode('/', $value, 2)); + $range = $chunks[0]; + $step = isset($chunks[1]) ? $chunks[1] : 0; + + // No step or 0 steps aren't cool + if (is_null($step) || '0' === $step || 0 === $step) { + return false; + } + + // Expand the * to a full range + if ('*' == $range) { + $range = $this->rangeStart . '-' . $this->rangeEnd; + } + + // Generate the requested small range + $rangeChunks = explode('-', $range, 2); + $rangeStart = $rangeChunks[0]; + $rangeEnd = isset($rangeChunks[1]) ? $rangeChunks[1] : $rangeStart; + + if ($rangeStart < $this->rangeStart || $rangeStart > $this->rangeEnd || $rangeStart > $rangeEnd) { + throw new \OutOfRangeException('Invalid range start requested'); + } + + if ($rangeEnd < $this->rangeStart || $rangeEnd > $this->rangeEnd || $rangeEnd < $rangeStart) { + throw new \OutOfRangeException('Invalid range end requested'); + } + + // Steps larger than the range need to wrap around and be handled slightly differently than smaller steps + if ($step >= $this->rangeEnd) { + $thisRange = [$this->fullRange[$step % count($this->fullRange)]]; + } else { + $thisRange = range($rangeStart, $rangeEnd, $step); + } + + return in_array($dateValue, $thisRange); + } + + /** + * Returns a range of values for the given cron expression + * + * @param string $expression The expression to evaluate + * @param int $max Maximum offset for range + * + * @return array + */ + public function getRangeForExpression($expression, $max) + { + $values = array(); + $expression = $this->convertLiterals($expression); + + if (strpos($expression, ',') !== false) { + $ranges = explode(',', $expression); + $values = []; + foreach ($ranges as $range) { + $expanded = $this->getRangeForExpression($range, $this->rangeEnd); + $values = array_merge($values, $expanded); + } + return $values; + } + + if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) { + if (!$this->isIncrementsOfRanges($expression)) { + list ($offset, $to) = explode('-', $expression); + $offset = $this->convertLiterals($offset); + $to = $this->convertLiterals($to); + $stepSize = 1; + } + else { + $range = array_map('trim', explode('/', $expression, 2)); + $stepSize = isset($range[1]) ? $range[1] : 0; + $range = $range[0]; + $range = explode('-', $range, 2); + $offset = $range[0]; + $to = isset($range[1]) ? $range[1] : $max; + } + $offset = $offset == '*' ? $this->rangeStart : $offset; + if ($stepSize >= $this->rangeEnd) { + $values = [$this->fullRange[$stepSize % count($this->fullRange)]]; + } else { + for ($i = $offset; $i <= $to; $i += $stepSize) { + $values[] = (int)$i; + } + } + sort($values); + } + else { + $values = array($expression); + } + + return $values; + } + + /** + * Convert literal + * + * @param string $value + * @return string + */ + protected function convertLiterals($value) + { + if (count($this->literals)) { + $key = array_search($value, $this->literals); + if ($key !== false) { + return (string) $key; + } + } + + return $value; + } + + /** + * Checks to see if a value is valid for the field + * + * @param string $value + * @return bool + */ + public function validate($value) + { + $value = $this->convertLiterals($value); + + // All fields allow * as a valid value + if ('*' === $value) { + return true; + } + + if (strpos($value, '/') !== false) { + list($range, $step) = explode('/', $value); + return $this->validate($range) && filter_var($step, FILTER_VALIDATE_INT); + } + + // Validate each chunk of a list individually + if (strpos($value, ',') !== false) { + foreach (explode(',', $value) as $listItem) { + if (!$this->validate($listItem)) { + return false; + } + } + return true; + } + + if (strpos($value, '-') !== false) { + if (substr_count($value, '-') > 1) { + return false; + } + + $chunks = explode('-', $value); + $chunks[0] = $this->convertLiterals($chunks[0]); + $chunks[1] = $this->convertLiterals($chunks[1]); + + if ('*' == $chunks[0] || '*' == $chunks[1]) { + return false; + } + + return $this->validate($chunks[0]) && $this->validate($chunks[1]); + } + + if (!is_numeric($value)) { + return false; + } + + if (is_float($value) || strpos($value, '.') !== false) { + return false; + } + + // We should have a numeric by now, so coerce this into an integer + $value = (int) $value; + + return in_array($value, $this->fullRange, true); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php new file mode 100644 index 0000000000..594b435825 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php @@ -0,0 +1,413 @@ + '0 0 1 1 *', + '@annually' => '0 0 1 1 *', + '@monthly' => '0 0 1 * *', + '@weekly' => '0 0 * * 0', + '@daily' => '0 0 * * *', + '@hourly' => '0 * * * *' + ); + + if (isset($mappings[$expression])) { + $expression = $mappings[$expression]; + } + + return new static($expression, $fieldFactory ?: new FieldFactory()); + } + + /** + * Validate a CronExpression. + * + * @param string $expression The CRON expression to validate. + * + * @return bool True if a valid CRON expression was passed. False if not. + * @see \Cron\CronExpression::factory + */ + public static function isValidExpression($expression) + { + try { + self::factory($expression); + } catch (InvalidArgumentException $e) { + return false; + } + + return true; + } + + /** + * Parse a CRON expression + * + * @param string $expression CRON expression (e.g. '8 * * * *') + * @param FieldFactory|null $fieldFactory Factory to create cron fields + */ + public function __construct($expression, FieldFactory $fieldFactory = null) + { + $this->fieldFactory = $fieldFactory; + $this->setExpression($expression); + } + + /** + * Set or change the CRON expression + * + * @param string $value CRON expression (e.g. 8 * * * *) + * + * @return CronExpression + * @throws \InvalidArgumentException if not a valid CRON expression + */ + public function setExpression($value) + { + $this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY); + if (count($this->cronParts) < 5) { + throw new InvalidArgumentException( + $value . ' is not a valid CRON expression' + ); + } + + foreach ($this->cronParts as $position => $part) { + $this->setPart($position, $part); + } + + return $this; + } + + /** + * Set part of the CRON expression + * + * @param int $position The position of the CRON expression to set + * @param string $value The value to set + * + * @return CronExpression + * @throws \InvalidArgumentException if the value is not valid for the part + */ + public function setPart($position, $value) + { + if (!$this->fieldFactory->getField($position)->validate($value)) { + throw new InvalidArgumentException( + 'Invalid CRON field value ' . $value . ' at position ' . $position + ); + } + + $this->cronParts[$position] = $value; + + return $this; + } + + /** + * Set max iteration count for searching next run dates + * + * @param int $maxIterationCount Max iteration count when searching for next run date + * + * @return CronExpression + */ + public function setMaxIterationCount($maxIterationCount) + { + $this->maxIterationCount = $maxIterationCount; + + return $this; + } + + /** + * Get a next run date relative to the current date or a specific date + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning a + * matching next run date. 0, the default, will return the + * current date and time if the next run date falls on the + * current date and time. Setting this value to 1 will + * skip the first match and go to the second match. + * Setting this value to 2 will skip the first 2 + * matches and so on. + * @param bool $allowCurrentDate Set to TRUE to return the current date if + * it matches the cron expression. + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return \DateTime + * @throws \RuntimeException on too many iterations + */ + public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false, $timeZone = null) + { + return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate, $timeZone); + } + + /** + * Get a previous run date relative to the current date or a specific date + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return \DateTime + * @throws \RuntimeException on too many iterations + * @see \Cron\CronExpression::getNextRunDate + */ + public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false, $timeZone = null) + { + return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate, $timeZone); + } + + /** + * Get multiple run dates starting at the current date or a specific date + * + * @param int $total Set the total number of dates to calculate + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param bool $invert Set to TRUE to retrieve previous dates + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return \DateTime[] Returns an array of run dates + */ + public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false, $timeZone = null) + { + $matches = array(); + for ($i = 0; $i < max(0, $total); $i++) { + try { + $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate, $timeZone); + } catch (RuntimeException $e) { + break; + } + } + + return $matches; + } + + /** + * Get all or part of the CRON expression + * + * @param string $part Specify the part to retrieve or NULL to get the full + * cron schedule string. + * + * @return string|null Returns the CRON expression, a part of the + * CRON expression, or NULL if the part was specified but not found + */ + public function getExpression($part = null) + { + if (null === $part) { + return implode(' ', $this->cronParts); + } elseif (array_key_exists($part, $this->cronParts)) { + return $this->cronParts[$part]; + } + + return null; + } + + /** + * Helper method to output the full expression. + * + * @return string Full CRON expression + */ + public function __toString() + { + return $this->getExpression(); + } + + /** + * Determine if the cron is due to run based on the current date or a + * specific date. This method assumes that the current number of + * seconds are irrelevant, and should be called once per minute. + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return bool Returns TRUE if the cron is due to run or FALSE if not + */ + public function isDue($currentTime = 'now', $timeZone = null) + { + $timeZone = $this->determineTimeZone($currentTime, $timeZone); + + if ('now' === $currentTime) { + $currentTime = new DateTime(); + } elseif ($currentTime instanceof DateTime) { + // + } elseif ($currentTime instanceof DateTimeImmutable) { + $currentTime = DateTime::createFromFormat('U', $currentTime->format('U')); + } else { + $currentTime = new DateTime($currentTime); + } + $currentTime->setTimeZone(new DateTimeZone($timeZone)); + + // drop the seconds to 0 + $currentTime = DateTime::createFromFormat('Y-m-d H:i', $currentTime->format('Y-m-d H:i')); + + try { + return $this->getNextRunDate($currentTime, 0, true)->getTimestamp() === $currentTime->getTimestamp(); + } catch (Exception $e) { + return false; + } + } + + /** + * Get the next or previous run date of the expression relative to a date + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning + * @param bool $invert Set to TRUE to go backwards in time + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param string|null $timeZone TimeZone to use instead of the system default + * + * @return \DateTime + * @throws \RuntimeException on too many iterations + */ + protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false, $timeZone = null) + { + $timeZone = $this->determineTimeZone($currentTime, $timeZone); + + if ($currentTime instanceof DateTime) { + $currentDate = clone $currentTime; + } elseif ($currentTime instanceof DateTimeImmutable) { + $currentDate = DateTime::createFromFormat('U', $currentTime->format('U')); + } else { + $currentDate = new DateTime($currentTime ?: 'now'); + } + + $currentDate->setTimeZone(new DateTimeZone($timeZone)); + $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0); + $nextRun = clone $currentDate; + $nth = (int) $nth; + + // We don't have to satisfy * or null fields + $parts = array(); + $fields = array(); + foreach (self::$order as $position) { + $part = $this->getExpression($position); + if (null === $part || '*' === $part) { + continue; + } + $parts[$position] = $part; + $fields[$position] = $this->fieldFactory->getField($position); + } + + // Set a hard limit to bail on an impossible date + for ($i = 0; $i < $this->maxIterationCount; $i++) { + + foreach ($parts as $position => $part) { + $satisfied = false; + // Get the field object used to validate this part + $field = $fields[$position]; + // Check if this is singular or a list + if (strpos($part, ',') === false) { + $satisfied = $field->isSatisfiedBy($nextRun, $part); + } else { + foreach (array_map('trim', explode(',', $part)) as $listPart) { + if ($field->isSatisfiedBy($nextRun, $listPart)) { + $satisfied = true; + break; + } + } + } + + // If the field is not satisfied, then start over + if (!$satisfied) { + $field->increment($nextRun, $invert, $part); + continue 2; + } + } + + // Skip this match if needed + if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) { + $this->fieldFactory->getField(0)->increment($nextRun, $invert, isset($parts[0]) ? $parts[0] : null); + continue; + } + + return $nextRun; + } + + // @codeCoverageIgnoreStart + throw new RuntimeException('Impossible CRON expression'); + // @codeCoverageIgnoreEnd + } + + /** + * Workout what timeZone should be used. + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param string|null $timeZone TimeZone to use instead of the system default + * + * @return string + */ + protected function determineTimeZone($currentTime, $timeZone) + { + if (! is_null($timeZone)) { + return $timeZone; + } + + if ($currentTime instanceOf DateTimeInterface) { + return $currentTime->getTimeZone()->getName(); + } + + return date_default_timezone_get(); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php new file mode 100644 index 0000000000..d4552e06be --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php @@ -0,0 +1,145 @@ + + */ +class DayOfMonthField extends AbstractField +{ + /** + * @inheritDoc + */ + protected $rangeStart = 1; + + /** + * @inheritDoc + */ + protected $rangeEnd = 31; + + /** + * Get the nearest day of the week for a given day in a month + * + * @param int $currentYear Current year + * @param int $currentMonth Current month + * @param int $targetDay Target day of the month + * + * @return \DateTime Returns the nearest date + */ + private static function getNearestWeekday($currentYear, $currentMonth, $targetDay) + { + $tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT); + $target = DateTime::createFromFormat('Y-m-d', "$currentYear-$currentMonth-$tday"); + $currentWeekday = (int) $target->format('N'); + + if ($currentWeekday < 6) { + return $target; + } + + $lastDayOfMonth = $target->format('t'); + + foreach (array(-1, 1, -2, 2) as $i) { + $adjusted = $targetDay + $i; + if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) { + $target->setDate($currentYear, $currentMonth, $adjusted); + if ($target->format('N') < 6 && $target->format('m') == $currentMonth) { + return $target; + } + } + } + } + + /** + * @inheritDoc + */ + public function isSatisfiedBy(DateTimeInterface $date, $value) + { + // ? states that the field value is to be skipped + if ($value == '?') { + return true; + } + + $fieldValue = $date->format('d'); + + // Check to see if this is the last day of the month + if ($value == 'L') { + return $fieldValue == $date->format('t'); + } + + // Check to see if this is the nearest weekday to a particular value + if (strpos($value, 'W')) { + // Parse the target day + $targetDay = substr($value, 0, strpos($value, 'W')); + // Find out if the current day is the nearest day of the week + return $date->format('j') == self::getNearestWeekday( + $date->format('Y'), + $date->format('m'), + $targetDay + )->format('j'); + } + + return $this->isSatisfied($date->format('d'), $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable &$date + */ + public function increment(DateTimeInterface &$date, $invert = false) + { + if ($invert) { + $date = $date->modify('previous day')->setTime(23, 59); + } else { + $date = $date->modify('next day')->setTime(0, 0); + } + + return $this; + } + + /** + * @inheritDoc + */ + public function validate($value) + { + $basicChecks = parent::validate($value); + + // Validate that a list don't have W or L + if (strpos($value, ',') !== false && (strpos($value, 'W') !== false || strpos($value, 'L') !== false)) { + return false; + } + + if (!$basicChecks) { + + if ($value === 'L') { + return true; + } + + if (preg_match('/^(.*)W$/', $value, $matches)) { + return $this->validate($matches[1]); + } + + return false; + } + + return $basicChecks; + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php new file mode 100644 index 0000000000..d4ba3156ec --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php @@ -0,0 +1,196 @@ + 'MON', 2 => 'TUE', 3 => 'WED', 4 => 'THU', 5 => 'FRI', 6 => 'SAT', 7 => 'SUN']; + + /** + * Constructor + */ + public function __construct() + { + $this->nthRange = range(1, 5); + parent::__construct(); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable $date + */ + public function isSatisfiedBy(DateTimeInterface $date, $value) + { + if ($value == '?') { + return true; + } + + // Convert text day of the week values to integers + $value = $this->convertLiterals($value); + + $currentYear = $date->format('Y'); + $currentMonth = $date->format('m'); + $lastDayOfMonth = $date->format('t'); + + // Find out if this is the last specific weekday of the month + if (strpos($value, 'L')) { + $weekday = (int) $this->convertLiterals(substr($value, 0, strpos($value, 'L'))); + $weekday %= 7; + + $tdate = clone $date; + $tdate = $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth); + while ($tdate->format('w') != $weekday) { + $tdateClone = new DateTime(); + $tdate = $tdateClone + ->setTimezone($tdate->getTimezone()) + ->setDate($currentYear, $currentMonth, --$lastDayOfMonth); + } + + return $date->format('j') == $lastDayOfMonth; + } + + // Handle # hash tokens + if (strpos($value, '#')) { + list($weekday, $nth) = explode('#', $value); + + if (!is_numeric($nth)) { + throw new InvalidArgumentException("Hashed weekdays must be numeric, {$nth} given"); + } else { + $nth = (int) $nth; + } + + // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601 + if ($weekday === '0') { + $weekday = 7; + } + + $weekday = $this->convertLiterals($weekday); + + // Validate the hash fields + if ($weekday < 0 || $weekday > 7) { + throw new InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given"); + } + + if (!in_array($nth, $this->nthRange)) { + throw new InvalidArgumentException("There are never more than 5 or less than 1 of a given weekday in a month, {$nth} given"); + } + + // The current weekday must match the targeted weekday to proceed + if ($date->format('N') != $weekday) { + return false; + } + + $tdate = clone $date; + $tdate = $tdate->setDate($currentYear, $currentMonth, 1); + $dayCount = 0; + $currentDay = 1; + while ($currentDay < $lastDayOfMonth + 1) { + if ($tdate->format('N') == $weekday) { + if (++$dayCount >= $nth) { + break; + } + } + $tdate = $tdate->setDate($currentYear, $currentMonth, ++$currentDay); + } + + return $date->format('j') == $currentDay; + } + + // Handle day of the week values + if (strpos($value, '-')) { + $parts = explode('-', $value); + if ($parts[0] == '7') { + $parts[0] = '0'; + } elseif ($parts[1] == '0') { + $parts[1] = '7'; + } + $value = implode('-', $parts); + } + + // Test to see which Sunday to use -- 0 == 7 == Sunday + $format = in_array(7, str_split($value)) ? 'N' : 'w'; + $fieldValue = $date->format($format); + + return $this->isSatisfied($fieldValue, $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable &$date + */ + public function increment(DateTimeInterface &$date, $invert = false) + { + if ($invert) { + $date = $date->modify('-1 day')->setTime(23, 59, 0); + } else { + $date = $date->modify('+1 day')->setTime(0, 0, 0); + } + + return $this; + } + + /** + * @inheritDoc + */ + public function validate($value) + { + $basicChecks = parent::validate($value); + + if (!$basicChecks) { + // Handle the # value + if (strpos($value, '#') !== false) { + $chunks = explode('#', $value); + $chunks[0] = $this->convertLiterals($chunks[0]); + + if (parent::validate($chunks[0]) && is_numeric($chunks[1]) && in_array($chunks[1], $this->nthRange)) { + return true; + } + } + + if (preg_match('/^(.*)L$/', $value, $matches)) { + return $this->validate($matches[1]); + } + + return false; + } + + return $basicChecks; + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php new file mode 100644 index 0000000000..545e4b837c --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php @@ -0,0 +1,54 @@ +fields[$position])) { + switch ($position) { + case 0: + $this->fields[$position] = new MinutesField(); + break; + case 1: + $this->fields[$position] = new HoursField(); + break; + case 2: + $this->fields[$position] = new DayOfMonthField(); + break; + case 3: + $this->fields[$position] = new MonthField(); + break; + case 4: + $this->fields[$position] = new DayOfWeekField(); + break; + default: + throw new InvalidArgumentException( + ($position + 1) . ' is not a valid position' + ); + } + } + + return $this->fields[$position]; + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldInterface.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldInterface.php new file mode 100644 index 0000000000..f8366eae7b --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/FieldInterface.php @@ -0,0 +1,41 @@ +isSatisfied($date->format('H'), $value); + } + + /** + * {@inheritDoc} + * + * @param \DateTime|\DateTimeImmutable &$date + * @param string|null $parts + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null) + { + // Change timezone to UTC temporarily. This will + // allow us to go back or forwards and hour even + // if DST will be changed between the hours. + if (is_null($parts) || $parts == '*') { + $timezone = $date->getTimezone(); + $date = $date->setTimezone(new DateTimeZone('UTC')); + $date = $date->modify(($invert ? '-' : '+') . '1 hour'); + $date = $date->setTimezone($timezone); + + $date = $date->setTime($date->format('H'), $invert ? 59 : 0); + return $this; + } + + $parts = strpos($parts, ',') !== false ? explode(',', $parts) : array($parts); + $hours = array(); + foreach ($parts as $part) { + $hours = array_merge($hours, $this->getRangeForExpression($part, 23)); + } + + $current_hour = $date->format('H'); + $position = $invert ? count($hours) - 1 : 0; + if (count($hours) > 1) { + for ($i = 0; $i < count($hours) - 1; $i++) { + if ((!$invert && $current_hour >= $hours[$i] && $current_hour < $hours[$i + 1]) || + ($invert && $current_hour > $hours[$i] && $current_hour <= $hours[$i + 1])) { + $position = $invert ? $i : $i + 1; + break; + } + } + } + + $hour = $hours[$position]; + if ((!$invert && $date->format('H') >= $hour) || ($invert && $date->format('H') <= $hour)) { + $date = $date->modify(($invert ? '-' : '+') . '1 day'); + $date = $date->setTime($invert ? 23 : 0, $invert ? 59 : 0); + } + else { + $date = $date->setTime($hour, $invert ? 59 : 0); + } + + return $this; + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php new file mode 100644 index 0000000000..fecc9b6da7 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php @@ -0,0 +1,75 @@ +isSatisfied($date->format('i'), $value); + } + + /** + * {@inheritDoc} + * + * @param \DateTime|\DateTimeImmutable &$date + * @param string|null $parts + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null) + { + if (is_null($parts)) { + $date = $date->modify(($invert ? '-' : '+') . '1 minute'); + return $this; + } + + $parts = strpos($parts, ',') !== false ? explode(',', $parts) : array($parts); + $minutes = array(); + foreach ($parts as $part) { + $minutes = array_merge($minutes, $this->getRangeForExpression($part, 59)); + } + + $current_minute = $date->format('i'); + $position = $invert ? count($minutes) - 1 : 0; + if (count($minutes) > 1) { + for ($i = 0; $i < count($minutes) - 1; $i++) { + if ((!$invert && $current_minute >= $minutes[$i] && $current_minute < $minutes[$i + 1]) || + ($invert && $current_minute > $minutes[$i] && $current_minute <= $minutes[$i + 1])) { + $position = $invert ? $i : $i + 1; + break; + } + } + } + + if ((!$invert && $current_minute >= $minutes[$position]) || ($invert && $current_minute <= $minutes[$position])) { + $date = $date->modify(($invert ? '-' : '+') . '1 hour'); + $date = $date->setTime($date->format('H'), $invert ? 59 : 0); + } + else { + $date = $date->setTime($date->format('H'), $minutes[$position]); + } + + return $this; + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php b/lib/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php new file mode 100644 index 0000000000..afc9caff23 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php @@ -0,0 +1,59 @@ + 'JAN', 2 => 'FEB', 3 => 'MAR', 4 => 'APR', 5 => 'MAY', 6 => 'JUN', 7 => 'JUL', + 8 => 'AUG', 9 => 'SEP', 10 => 'OCT', 11 => 'NOV', 12 => 'DEC']; + + /** + * @inheritDoc + */ + public function isSatisfiedBy(DateTimeInterface $date, $value) + { + if ($value == '?') { + return true; + } + + $value = $this->convertLiterals($value); + + return $this->isSatisfied($date->format('m'), $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable &$date + */ + public function increment(DateTimeInterface &$date, $invert = false) + { + if ($invert) { + $date = $date->modify('last day of previous month')->setTime(23, 59); + } else { + $date = $date->modify('first day of next month')->setTime(0, 0); + } + + return $this; + } + + +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/AbstractFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/AbstractFieldTest.php new file mode 100644 index 0000000000..38114392eb --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/AbstractFieldTest.php @@ -0,0 +1,139 @@ + + */ +class AbstractFieldTest extends TestCase +{ + /** + * @covers \Cron\AbstractField::isRange + */ + public function testTestsIfRange() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isRange('1-2')); + $this->assertFalse($f->isRange('2')); + } + + /** + * @covers \Cron\AbstractField::isIncrementsOfRanges + */ + public function testTestsIfIncrementsOfRanges() + { + $f = new DayOfWeekField(); + $this->assertFalse($f->isIncrementsOfRanges('1-2')); + $this->assertTrue($f->isIncrementsOfRanges('1/2')); + $this->assertTrue($f->isIncrementsOfRanges('*/2')); + $this->assertTrue($f->isIncrementsOfRanges('3-12/2')); + } + + /** + * @covers \Cron\AbstractField::isInRange + */ + public function testTestsIfInRange() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isInRange('1', '1-2')); + $this->assertTrue($f->isInRange('2', '1-2')); + $this->assertTrue($f->isInRange('5', '4-12')); + $this->assertFalse($f->isInRange('3', '4-12')); + $this->assertFalse($f->isInRange('13', '4-12')); + } + + /** + * @covers \Cron\AbstractField::isInIncrementsOfRanges + */ + public function testTestsIfInIncrementsOfRangesOnZeroStartRange() + { + $f = new MinutesField(); + $this->assertTrue($f->isInIncrementsOfRanges('3', '3-59/2')); + $this->assertTrue($f->isInIncrementsOfRanges('13', '3-59/2')); + $this->assertTrue($f->isInIncrementsOfRanges('15', '3-59/2')); + $this->assertTrue($f->isInIncrementsOfRanges('14', '*/2')); + $this->assertFalse($f->isInIncrementsOfRanges('2', '3-59/13')); + $this->assertFalse($f->isInIncrementsOfRanges('14', '*/13')); + $this->assertFalse($f->isInIncrementsOfRanges('14', '3-59/2')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '2-59')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '2')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '*')); + $this->assertFalse($f->isInIncrementsOfRanges('0', '*/0')); + $this->assertFalse($f->isInIncrementsOfRanges('1', '*/0')); + + $this->assertTrue($f->isInIncrementsOfRanges('4', '4/1')); + $this->assertFalse($f->isInIncrementsOfRanges('14', '4/1')); + $this->assertFalse($f->isInIncrementsOfRanges('34', '4/1')); + } + + /** + * @covers \Cron\AbstractField::isInIncrementsOfRanges + */ + public function testTestsIfInIncrementsOfRangesOnOneStartRange() + { + $f = new MonthField(); + $this->assertTrue($f->isInIncrementsOfRanges('3', '3-12/2')); + $this->assertFalse($f->isInIncrementsOfRanges('13', '3-12/2')); + $this->assertFalse($f->isInIncrementsOfRanges('15', '3-12/2')); + $this->assertTrue($f->isInIncrementsOfRanges('3', '*/2')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '*/3')); + $this->assertTrue($f->isInIncrementsOfRanges('7', '*/3')); + $this->assertFalse($f->isInIncrementsOfRanges('14', '3-12/2')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '2-12')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '2')); + $this->assertFalse($f->isInIncrementsOfRanges('3', '*')); + $this->assertFalse($f->isInIncrementsOfRanges('0', '*/0')); + $this->assertFalse($f->isInIncrementsOfRanges('1', '*/0')); + + $this->assertTrue($f->isInIncrementsOfRanges('4', '4/1')); + $this->assertFalse($f->isInIncrementsOfRanges('14', '4/1')); + $this->assertFalse($f->isInIncrementsOfRanges('34', '4/1')); + } + + /** + * @covers \Cron\AbstractField::isSatisfied + */ + public function testTestsIfSatisfied() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfied('12', '3-13')); + $this->assertFalse($f->isSatisfied('15', '3-7/2')); + $this->assertTrue($f->isSatisfied('12', '*')); + $this->assertTrue($f->isSatisfied('12', '12')); + $this->assertFalse($f->isSatisfied('12', '3-11')); + $this->assertFalse($f->isSatisfied('12', '3-7/2')); + $this->assertFalse($f->isSatisfied('12', '11')); + } + + /** + * Allows ranges and lists to coexist in the same expression + * + * @see https://github.com/dragonmantank/cron-expression/issues/5 + */ + public function testAllowRangesAndLists() + { + $expression = '5-7,11-13'; + $f = new HoursField(); + $this->assertTrue($f->validate($expression)); + } + + /** + * Makes sure that various types of ranges expand out properly + * + * @see https://github.com/dragonmantank/cron-expression/issues/5 + */ + public function testGetRangeForExpressionExpandsCorrectly() + { + $f = new HoursField(); + $this->assertSame([5, 6, 7, 11, 12, 13], $f->getRangeForExpression('5-7,11-13', 23)); + $this->assertSame(['5', '6', '7', '11', '12', '13'], $f->getRangeForExpression('5,6,7,11,12,13', 23)); + $this->assertSame([0, 6, 12, 18], $f->getRangeForExpression('*/6', 23)); + $this->assertSame([5, 11], $f->getRangeForExpression('5-13/6', 23)); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/CronExpressionTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/CronExpressionTest.php new file mode 100644 index 0000000000..8810d43da6 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/CronExpressionTest.php @@ -0,0 +1,589 @@ + + */ +class CronExpressionTest extends TestCase +{ + /** + * @covers \Cron\CronExpression::factory + */ + public function testFactoryRecognizesTemplates() + { + $this->assertSame('0 0 1 1 *', CronExpression::factory('@annually')->getExpression()); + $this->assertSame('0 0 1 1 *', CronExpression::factory('@yearly')->getExpression()); + $this->assertSame('0 0 * * 0', CronExpression::factory('@weekly')->getExpression()); + } + + /** + * @covers \Cron\CronExpression::__construct + * @covers \Cron\CronExpression::getExpression + * @covers \Cron\CronExpression::__toString + */ + public function testParsesCronSchedule() + { + // '2010-09-10 12:00:00' + $cron = CronExpression::factory('1 2-4 * 4,5,6 */3'); + $this->assertSame('1', $cron->getExpression(CronExpression::MINUTE)); + $this->assertSame('2-4', $cron->getExpression(CronExpression::HOUR)); + $this->assertSame('*', $cron->getExpression(CronExpression::DAY)); + $this->assertSame('4,5,6', $cron->getExpression(CronExpression::MONTH)); + $this->assertSame('*/3', $cron->getExpression(CronExpression::WEEKDAY)); + $this->assertSame('1 2-4 * 4,5,6 */3', $cron->getExpression()); + $this->assertSame('1 2-4 * 4,5,6 */3', (string) $cron); + $this->assertNull($cron->getExpression('foo')); + } + + /** + * @covers \Cron\CronExpression::__construct + * @covers \Cron\CronExpression::getExpression + * @covers \Cron\CronExpression::__toString + */ + public function testParsesCronScheduleThrowsAnException() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid CRON field value A at position 0'); + + CronExpression::factory('A 1 2 3 4'); + } + + /** + * @covers \Cron\CronExpression::__construct + * @covers \Cron\CronExpression::getExpression + * @dataProvider scheduleWithDifferentSeparatorsProvider + */ + public function testParsesCronScheduleWithAnySpaceCharsAsSeparators($schedule, array $expected) + { + $cron = CronExpression::factory($schedule); + $this->assertSame($expected[0], $cron->getExpression(CronExpression::MINUTE)); + $this->assertSame($expected[1], $cron->getExpression(CronExpression::HOUR)); + $this->assertSame($expected[2], $cron->getExpression(CronExpression::DAY)); + $this->assertSame($expected[3], $cron->getExpression(CronExpression::MONTH)); + $this->assertSame($expected[4], $cron->getExpression(CronExpression::WEEKDAY)); + } + + /** + * Data provider for testParsesCronScheduleWithAnySpaceCharsAsSeparators + * + * @return array + */ + public static function scheduleWithDifferentSeparatorsProvider() + { + return array( + array("*\t*\t*\t*\t*\t", array('*', '*', '*', '*', '*', '*')), + array("* * * * * ", array('*', '*', '*', '*', '*', '*')), + array("* \t * \t * \t * \t * \t", array('*', '*', '*', '*', '*', '*')), + array("*\t \t*\t \t*\t \t*\t \t*\t \t", array('*', '*', '*', '*', '*', '*')), + ); + } + + /** + * @covers \Cron\CronExpression::__construct + * @covers \Cron\CronExpression::setExpression + * @covers \Cron\CronExpression::setPart + */ + public function testInvalidCronsWillFail() + { + $this->expectException(\InvalidArgumentException::class); + + // Only four values + $cron = CronExpression::factory('* * * 1'); + } + + /** + * @covers \Cron\CronExpression::setPart + */ + public function testInvalidPartsWillFail() + { + $this->expectException(\InvalidArgumentException::class); + + // Only four values + $cron = CronExpression::factory('* * * * *'); + $cron->setPart(1, 'abc'); + } + + /** + * Data provider for cron schedule + * + * @return array + */ + public function scheduleProvider() + { + return array( + array('*/2 */2 * * *', '2015-08-10 21:47:27', '2015-08-10 22:00:00', false), + array('* * * * *', '2015-08-10 21:50:37', '2015-08-10 21:50:00', true), + array('* 20,21,22 * * *', '2015-08-10 21:50:00', '2015-08-10 21:50:00', true), + // Handles CSV values + array('* 20,22 * * *', '2015-08-10 21:50:00', '2015-08-10 22:00:00', false), + // CSV values can be complex + array('7-9 * */9 * *', '2015-08-10 22:02:33', '2015-08-10 22:07:00', false), + // 15th minute, of the second hour, every 15 days, in January, every Friday + array('1 * * * 7', '2015-08-10 21:47:27', '2015-08-16 00:01:00', false), + // Test with exact times + array('47 21 * * *', strtotime('2015-08-10 21:47:30'), '2015-08-10 21:47:00', true), + // Test Day of the week (issue #1) + // According cron implementation, 0|7 = sunday, 1 => monday, etc + array('* * * * 0', strtotime('2011-06-15 23:09:00'), '2011-06-19 00:00:00', false), + array('* * * * 7', strtotime('2011-06-15 23:09:00'), '2011-06-19 00:00:00', false), + array('* * * * 1', strtotime('2011-06-15 23:09:00'), '2011-06-20 00:00:00', false), + // Should return the sunday date as 7 equals 0 + array('0 0 * * MON,SUN', strtotime('2011-06-15 23:09:00'), '2011-06-19 00:00:00', false), + array('0 0 * * 1,7', strtotime('2011-06-15 23:09:00'), '2011-06-19 00:00:00', false), + array('0 0 * * 0-4', strtotime('2011-06-15 23:09:00'), '2011-06-16 00:00:00', false), + array('0 0 * * 7-4', strtotime('2011-06-15 23:09:00'), '2011-06-16 00:00:00', false), + array('0 0 * * 4-7', strtotime('2011-06-15 23:09:00'), '2011-06-16 00:00:00', false), + array('0 0 * * 7-3', strtotime('2011-06-15 23:09:00'), '2011-06-19 00:00:00', false), + array('0 0 * * 3-7', strtotime('2011-06-15 23:09:00'), '2011-06-16 00:00:00', false), + array('0 0 * * 3-7', strtotime('2011-06-18 23:09:00'), '2011-06-19 00:00:00', false), + // Test lists of values and ranges (Abhoryo) + array('0 0 * * 2-7', strtotime('2011-06-20 23:09:00'), '2011-06-21 00:00:00', false), + array('0 0 * * 2-7', strtotime('2011-06-18 23:09:00'), '2011-06-19 00:00:00', false), + array('0 0 * * 4-7', strtotime('2011-07-19 00:00:00'), '2011-07-21 00:00:00', false), + // Test increments of ranges + array('0-12/4 * * * *', strtotime('2011-06-20 12:04:00'), '2011-06-20 12:04:00', true), + array('4-59/2 * * * *', strtotime('2011-06-20 12:04:00'), '2011-06-20 12:04:00', true), + array('4-59/2 * * * *', strtotime('2011-06-20 12:06:00'), '2011-06-20 12:06:00', true), + array('4-59/3 * * * *', strtotime('2011-06-20 12:06:00'), '2011-06-20 12:07:00', false), + // Test Day of the Week and the Day of the Month (issue #1) + array('0 0 1 1 0', strtotime('2011-06-15 23:09:00'), '2012-01-01 00:00:00', false), + array('0 0 1 JAN 0', strtotime('2011-06-15 23:09:00'), '2012-01-01 00:00:00', false), + array('0 0 1 * 0', strtotime('2011-06-15 23:09:00'), '2012-01-01 00:00:00', false), + // Test the W day of the week modifier for day of the month field + array('0 0 2W * *', strtotime('2011-07-01 00:00:00'), '2011-07-01 00:00:00', true), + array('0 0 1W * *', strtotime('2011-05-01 00:00:00'), '2011-05-02 00:00:00', false), + array('0 0 1W * *', strtotime('2011-07-01 00:00:00'), '2011-07-01 00:00:00', true), + array('0 0 3W * *', strtotime('2011-07-01 00:00:00'), '2011-07-04 00:00:00', false), + array('0 0 16W * *', strtotime('2011-07-01 00:00:00'), '2011-07-15 00:00:00', false), + array('0 0 28W * *', strtotime('2011-07-01 00:00:00'), '2011-07-28 00:00:00', false), + array('0 0 30W * *', strtotime('2011-07-01 00:00:00'), '2011-07-29 00:00:00', false), + array('0 0 31W * *', strtotime('2011-07-01 00:00:00'), '2011-07-29 00:00:00', false), + // Test the last weekday of a month + array('* * * * 5L', strtotime('2011-07-01 00:00:00'), '2011-07-29 00:00:00', false), + array('* * * * 6L', strtotime('2011-07-01 00:00:00'), '2011-07-30 00:00:00', false), + array('* * * * 7L', strtotime('2011-07-01 00:00:00'), '2011-07-31 00:00:00', false), + array('* * * * 1L', strtotime('2011-07-24 00:00:00'), '2011-07-25 00:00:00', false), + array('* * * 1 5L', strtotime('2011-12-25 00:00:00'), '2012-01-27 00:00:00', false), + // Test the hash symbol for the nth weekday of a given month + array('* * * * 5#2', strtotime('2011-07-01 00:00:00'), '2011-07-08 00:00:00', false), + array('* * * * 5#1', strtotime('2011-07-01 00:00:00'), '2011-07-01 00:00:00', true), + array('* * * * 3#4', strtotime('2011-07-01 00:00:00'), '2011-07-27 00:00:00', false), + + // Issue #7, documented example failed + ['3-59/15 6-12 */15 1 2-5', strtotime('2017-01-08 00:00:00'), '2017-01-31 06:03:00', false], + + // https://github.com/laravel/framework/commit/07d160ac3cc9764d5b429734ffce4fa311385403 + ['* * * * MON-FRI', strtotime('2017-01-08 00:00:00'), strtotime('2017-01-09 00:00:00'), false], + ['* * * * TUE', strtotime('2017-01-08 00:00:00'), strtotime('2017-01-10 00:00:00'), false], + ); + } + + /** + * @covers \Cron\CronExpression::isDue + * @covers \Cron\CronExpression::getNextRunDate + * @covers \Cron\DayOfMonthField + * @covers \Cron\DayOfWeekField + * @covers \Cron\MinutesField + * @covers \Cron\HoursField + * @covers \Cron\MonthField + * @covers \Cron\CronExpression::getRunDate + * @dataProvider scheduleProvider + */ + public function testDeterminesIfCronIsDue($schedule, $relativeTime, $nextRun, $isDue) + { + $relativeTimeString = is_int($relativeTime) ? date('Y-m-d H:i:s', $relativeTime) : $relativeTime; + + // Test next run date + $cron = CronExpression::factory($schedule); + if (is_string($relativeTime)) { + $relativeTime = new DateTime($relativeTime); + } elseif (is_int($relativeTime)) { + $relativeTime = date('Y-m-d H:i:s', $relativeTime); + } + + if (is_string($nextRun)) { + $nextRunDate = new DateTime($nextRun); + } elseif (is_int($nextRun)) { + $nextRunDate = new DateTime(); + $nextRunDate->setTimestamp($nextRun); + } + $this->assertSame($isDue, $cron->isDue($relativeTime)); + $next = $cron->getNextRunDate($relativeTime, 0, true); + + $this->assertEquals($nextRunDate, $next); + } + + /** + * @covers \Cron\CronExpression::isDue + */ + public function testIsDueHandlesDifferentDates() + { + $cron = CronExpression::factory('* * * * *'); + $this->assertTrue($cron->isDue()); + $this->assertTrue($cron->isDue('now')); + $this->assertTrue($cron->isDue(new DateTime('now'))); + $this->assertTrue($cron->isDue(date('Y-m-d H:i'))); + $this->assertTrue($cron->isDue(new DateTimeImmutable('now'))); + } + + /** + * @covers \Cron\CronExpression::isDue + */ + public function testIsDueHandlesDifferentDefaultTimezones() + { + $originalTimezone = date_default_timezone_get(); + $cron = CronExpression::factory('0 15 * * 3'); //Wednesday at 15:00 + $date = '2014-01-01 15:00'; //Wednesday + + date_default_timezone_set('UTC'); + $this->assertTrue($cron->isDue(new DateTime($date), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date), 'Asia/Tokyo')); + + date_default_timezone_set('Europe/Amsterdam'); + $this->assertFalse($cron->isDue(new DateTime($date), 'UTC')); + $this->assertTrue($cron->isDue(new DateTime($date), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date), 'Asia/Tokyo')); + + date_default_timezone_set('Asia/Tokyo'); + $this->assertFalse($cron->isDue(new DateTime($date), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date), 'Europe/Amsterdam')); + $this->assertTrue($cron->isDue(new DateTime($date), 'Asia/Tokyo')); + + date_default_timezone_set($originalTimezone); + } + + /** + * @covers \Cron\CronExpression::isDue + */ + public function testIsDueHandlesDifferentSuppliedTimezones() + { + $cron = CronExpression::factory('0 15 * * 3'); //Wednesday at 15:00 + $date = '2014-01-01 15:00'; //Wednesday + + $this->assertTrue($cron->isDue(new DateTime($date, new DateTimeZone('UTC')), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('UTC')), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('UTC')), 'Asia/Tokyo')); + + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('Europe/Amsterdam')), 'UTC')); + $this->assertTrue($cron->isDue(new DateTime($date, new DateTimeZone('Europe/Amsterdam')), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('Europe/Amsterdam')), 'Asia/Tokyo')); + + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('Asia/Tokyo')), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date, new DateTimeZone('Asia/Tokyo')), 'Europe/Amsterdam')); + $this->assertTrue($cron->isDue(new DateTime($date, new DateTimeZone('Asia/Tokyo')), 'Asia/Tokyo')); + } + + /** + * @covers Cron\CronExpression::isDue + */ + public function testIsDueHandlesDifferentTimezonesAsArgument() + { + $cron = CronExpression::factory('0 15 * * 3'); //Wednesday at 15:00 + $date = '2014-01-01 15:00'; //Wednesday + $utc = new \DateTimeZone('UTC'); + $amsterdam = new \DateTimeZone('Europe/Amsterdam'); + $tokyo = new \DateTimeZone('Asia/Tokyo'); + $this->assertTrue($cron->isDue(new DateTime($date, $utc), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date, $amsterdam), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date, $tokyo), 'UTC')); + $this->assertFalse($cron->isDue(new DateTime($date, $utc), 'Europe/Amsterdam')); + $this->assertTrue($cron->isDue(new DateTime($date, $amsterdam), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date, $tokyo), 'Europe/Amsterdam')); + $this->assertFalse($cron->isDue(new DateTime($date, $utc), 'Asia/Tokyo')); + $this->assertFalse($cron->isDue(new DateTime($date, $amsterdam), 'Asia/Tokyo')); + $this->assertTrue($cron->isDue(new DateTime($date, $tokyo), 'Asia/Tokyo')); + } + + /** + * @covers Cron\CronExpression::isDue + */ + public function testRecognisesTimezonesAsPartOfDateTime() + { + $cron = CronExpression::factory("0 7 * * *"); + $tzCron = "America/New_York"; + $tzServer = new \DateTimeZone("Europe/London"); + + $dtCurrent = \DateTime::createFromFormat("!Y-m-d H:i:s", "2017-10-17 10:00:00", $tzServer); + $dtPrev = $cron->getPreviousRunDate($dtCurrent, 0, true, $tzCron); + $this->assertEquals('1508151600 : 2017-10-16T07:00:00-04:00 : America/New_York', $dtPrev->format("U \: c \: e")); + + $dtCurrent = \DateTimeImmutable::createFromFormat("!Y-m-d H:i:s", "2017-10-17 10:00:00", $tzServer); + $dtPrev = $cron->getPreviousRunDate($dtCurrent, 0, true, $tzCron); + $this->assertEquals('1508151600 : 2017-10-16T07:00:00-04:00 : America/New_York', $dtPrev->format("U \: c \: e")); + + $dtCurrent = \DateTimeImmutable::createFromFormat("!Y-m-d H:i:s", "2017-10-17 10:00:00", $tzServer); + $dtPrev = $cron->getPreviousRunDate($dtCurrent->format("c"), 0, true, $tzCron); + $this->assertEquals('1508151600 : 2017-10-16T07:00:00-04:00 : America/New_York', $dtPrev->format("U \: c \: e")); + + $dtCurrent = \DateTimeImmutable::createFromFormat("!Y-m-d H:i:s", "2017-10-17 10:00:00", $tzServer); + $dtPrev = $cron->getPreviousRunDate($dtCurrent->format("\@U"), 0, true, $tzCron); + $this->assertEquals('1508151600 : 2017-10-16T07:00:00-04:00 : America/New_York', $dtPrev->format("U \: c \: e")); + + } + + + /** + * @covers \Cron\CronExpression::getPreviousRunDate + */ + public function testCanGetPreviousRunDates() + { + $cron = CronExpression::factory('* * * * *'); + $next = $cron->getNextRunDate('now'); + $two = $cron->getNextRunDate('now', 1); + $this->assertEquals($next, $cron->getPreviousRunDate($two)); + + $cron = CronExpression::factory('* */2 * * *'); + $next = $cron->getNextRunDate('now'); + $two = $cron->getNextRunDate('now', 1); + $this->assertEquals($next, $cron->getPreviousRunDate($two)); + + $cron = CronExpression::factory('* * * */2 *'); + $next = $cron->getNextRunDate('now'); + $two = $cron->getNextRunDate('now', 1); + $this->assertEquals($next, $cron->getPreviousRunDate($two)); + } + + /** + * @covers \Cron\CronExpression::getMultipleRunDates + */ + public function testProvidesMultipleRunDates() + { + $cron = CronExpression::factory('*/2 * * * *'); + $this->assertEquals(array( + new DateTime('2008-11-09 00:00:00'), + new DateTime('2008-11-09 00:02:00'), + new DateTime('2008-11-09 00:04:00'), + new DateTime('2008-11-09 00:06:00') + ), $cron->getMultipleRunDates(4, '2008-11-09 00:00:00', false, true)); + } + + /** + * @covers \Cron\CronExpression::getMultipleRunDates + * @covers \Cron\CronExpression::setMaxIterationCount + */ + public function testProvidesMultipleRunDatesForTheFarFuture() { + // Fails with the default 1000 iteration limit + $cron = CronExpression::factory('0 0 12 1 *'); + $cron->setMaxIterationCount(2000); + $this->assertEquals(array( + new DateTime('2016-01-12 00:00:00'), + new DateTime('2017-01-12 00:00:00'), + new DateTime('2018-01-12 00:00:00'), + new DateTime('2019-01-12 00:00:00'), + new DateTime('2020-01-12 00:00:00'), + new DateTime('2021-01-12 00:00:00'), + new DateTime('2022-01-12 00:00:00'), + new DateTime('2023-01-12 00:00:00'), + new DateTime('2024-01-12 00:00:00'), + ), $cron->getMultipleRunDates(9, '2015-04-28 00:00:00', false, true)); + } + + /** + * @covers \Cron\CronExpression + */ + public function testCanIterateOverNextRuns() + { + $cron = CronExpression::factory('@weekly'); + $nextRun = $cron->getNextRunDate("2008-11-09 08:00:00"); + $this->assertEquals($nextRun, new DateTime("2008-11-16 00:00:00")); + + // true is cast to 1 + $nextRun = $cron->getNextRunDate("2008-11-09 00:00:00", true, true); + $this->assertEquals($nextRun, new DateTime("2008-11-16 00:00:00")); + + // You can iterate over them + $nextRun = $cron->getNextRunDate($cron->getNextRunDate("2008-11-09 00:00:00", 1, true), 1, true); + $this->assertEquals($nextRun, new DateTime("2008-11-23 00:00:00")); + + // You can skip more than one + $nextRun = $cron->getNextRunDate("2008-11-09 00:00:00", 2, true); + $this->assertEquals($nextRun, new DateTime("2008-11-23 00:00:00")); + $nextRun = $cron->getNextRunDate("2008-11-09 00:00:00", 3, true); + $this->assertEquals($nextRun, new DateTime("2008-11-30 00:00:00")); + } + + /** + * @covers \Cron\CronExpression::getRunDate + */ + public function testGetRunDateHandlesDifferentDates() + { + $cron = CronExpression::factory('@weekly'); + $date = new DateTime("2019-03-10 00:00:00"); + $this->assertEquals($date, $cron->getNextRunDate("2019-03-03 08:00:00")); + $this->assertEquals($date, $cron->getNextRunDate(new DateTime("2019-03-03 08:00:00"))); + $this->assertEquals($date, $cron->getNextRunDate(new DateTimeImmutable("2019-03-03 08:00:00"))); + } + + /** + * @covers \Cron\CronExpression::getRunDate + */ + public function testSkipsCurrentDateByDefault() + { + $cron = CronExpression::factory('* * * * *'); + $current = new DateTime('now'); + $next = $cron->getNextRunDate($current); + $nextPrev = $cron->getPreviousRunDate($next); + $this->assertSame($current->format('Y-m-d H:i:00'), $nextPrev->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\CronExpression::getRunDate + * @ticket 7 + */ + public function testStripsForSeconds() + { + $cron = CronExpression::factory('* * * * *'); + $current = new DateTime('2011-09-27 10:10:54'); + $this->assertSame('2011-09-27 10:11:00', $cron->getNextRunDate($current)->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\CronExpression::getRunDate + */ + public function testFixesPhpBugInDateIntervalMonth() + { + $cron = CronExpression::factory('0 0 27 JAN *'); + $this->assertSame('2011-01-27 00:00:00', $cron->getPreviousRunDate('2011-08-22 00:00:00')->format('Y-m-d H:i:s')); + } + + public function testIssue29() + { + $cron = CronExpression::factory('@weekly'); + $this->assertSame( + '2013-03-10 00:00:00', + $cron->getPreviousRunDate('2013-03-17 00:00:00')->format('Y-m-d H:i:s') + ); + } + + /** + * @see https://github.com/mtdowling/cron-expression/issues/20 + */ + public function testIssue20() { + $e = CronExpression::factory('* * * * MON#1'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 00:00:00'))); + $this->assertFalse($e->isDue(new DateTime('2014-04-14 00:00:00'))); + $this->assertFalse($e->isDue(new DateTime('2014-04-21 00:00:00'))); + + $e = CronExpression::factory('* * * * SAT#2'); + $this->assertFalse($e->isDue(new DateTime('2014-04-05 00:00:00'))); + $this->assertTrue($e->isDue(new DateTime('2014-04-12 00:00:00'))); + $this->assertFalse($e->isDue(new DateTime('2014-04-19 00:00:00'))); + + $e = CronExpression::factory('* * * * SUN#3'); + $this->assertFalse($e->isDue(new DateTime('2014-04-13 00:00:00'))); + $this->assertTrue($e->isDue(new DateTime('2014-04-20 00:00:00'))); + $this->assertFalse($e->isDue(new DateTime('2014-04-27 00:00:00'))); + } + + /** + * @covers \Cron\CronExpression::getRunDate + */ + public function testKeepOriginalTime() + { + $now = new \DateTime; + $strNow = $now->format(DateTime::ISO8601); + $cron = CronExpression::factory('0 0 * * *'); + $cron->getPreviousRunDate($now); + $this->assertSame($strNow, $now->format(DateTime::ISO8601)); + } + + /** + * @covers \Cron\CronExpression::__construct + * @covers \Cron\CronExpression::factory + * @covers \Cron\CronExpression::isValidExpression + * @covers \Cron\CronExpression::setExpression + * @covers \Cron\CronExpression::setPart + */ + public function testValidationWorks() + { + // Invalid. Only four values + $this->assertFalse(CronExpression::isValidExpression('* * * 1')); + // Valid + $this->assertTrue(CronExpression::isValidExpression('* * * * 1')); + + // Issue #156, 13 is an invalid month + $this->assertFalse(CronExpression::isValidExpression("* * * 13 * ")); + + // Issue #155, 90 is an invalid second + $this->assertFalse(CronExpression::isValidExpression('90 * * * *')); + + // Issue #154, 24 is an invalid hour + $this->assertFalse(CronExpression::isValidExpression("0 24 1 12 0")); + + // Issue #125, this is just all sorts of wrong + $this->assertFalse(CronExpression::isValidExpression('990 14 * * mon-fri0345345')); + + // see https://github.com/dragonmantank/cron-expression/issues/5 + $this->assertTrue(CronExpression::isValidExpression('2,17,35,47 5-7,11-13 * * *')); + } + + /** + * Makes sure that 00 is considered a valid value for 0-based fields + * cronie allows numbers with a leading 0, so adding support for this as well + * + * @see https://github.com/dragonmantank/cron-expression/issues/12 + */ + public function testDoubleZeroIsValid() + { + $this->assertTrue(CronExpression::isValidExpression('00 * * * *')); + $this->assertTrue(CronExpression::isValidExpression('01 * * * *')); + $this->assertTrue(CronExpression::isValidExpression('* 00 * * *')); + $this->assertTrue(CronExpression::isValidExpression('* 01 * * *')); + + $e = CronExpression::factory('00 * * * *'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 00:00:00'))); + $e = CronExpression::factory('01 * * * *'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 00:01:00'))); + + $e = CronExpression::factory('* 00 * * *'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 00:00:00'))); + $e = CronExpression::factory('* 01 * * *'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 01:00:00'))); + } + + + /** + * Ranges with large steps should "wrap around" to the appropriate value + * cronie allows for steps that are larger than the range of a field, with it wrapping around like a ring buffer. We + * should do the same. + * + * @see https://github.com/dragonmantank/cron-expression/issues/6 + */ + public function testRangesWrapAroundWithLargeSteps() + { + $f = new MonthField(); + $this->assertTrue($f->validate('*/123')); + $this->assertSame([4], $f->getRangeForExpression('*/123', 12)); + + $e = CronExpression::factory('* * * */123 *'); + $this->assertTrue($e->isDue(new DateTime('2014-04-07 00:00:00'))); + + $nextRunDate = $e->getNextRunDate(new DateTime('2014-04-07 00:00:00')); + $this->assertSame('2014-04-07 00:01:00', $nextRunDate->format('Y-m-d H:i:s')); + + $nextRunDate = $e->getNextRunDate(new DateTime('2014-05-07 00:00:00')); + $this->assertSame('2015-04-01 00:00:00', $nextRunDate->format('Y-m-d H:i:s')); + } + + /** + * When there is an issue with a field, we should report the human readable position + * + * @see https://github.com/dragonmantank/cron-expression/issues/29 + */ + public function testFieldPositionIsHumanAdjusted() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage("6 is not a valid position"); + $e = CronExpression::factory('0 * * * * ? *'); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfMonthFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfMonthFieldTest.php new file mode 100644 index 0000000000..2191b6bffa --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfMonthFieldTest.php @@ -0,0 +1,77 @@ + + */ +class DayOfMonthFieldTest extends TestCase +{ + /** + * @covers \Cron\DayOfMonthField::validate + */ + public function testValidatesField() + { + $f = new DayOfMonthField(); + $this->assertTrue($f->validate('1')); + $this->assertTrue($f->validate('*')); + $this->assertTrue($f->validate('L')); + $this->assertTrue($f->validate('5W')); + $this->assertTrue($f->validate('01')); + $this->assertFalse($f->validate('5W,L')); + $this->assertFalse($f->validate('1.')); + } + + /** + * @covers \Cron\DayOfMonthField::isSatisfiedBy + */ + public function testChecksIfSatisfied() + { + $f = new DayOfMonthField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '?')); + $this->assertTrue($f->isSatisfiedBy(new DateTimeImmutable(), '?')); + } + + /** + * @covers \Cron\DayOfMonthField::increment + */ + public function testIncrementsDate() + { + $d = new DateTime('2011-03-15 11:15:00'); + $f = new DayOfMonthField(); + $f->increment($d); + $this->assertSame('2011-03-16 00:00:00', $d->format('Y-m-d H:i:s')); + + $d = new DateTime('2011-03-15 11:15:00'); + $f->increment($d, true); + $this->assertSame('2011-03-14 23:59:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\DayOfMonthField::increment + */ + public function testIncrementsDateTimeImmutable() + { + $d = new DateTimeImmutable('2011-03-15 11:15:00'); + $f = new DayOfMonthField(); + $f->increment($d); + $this->assertSame('2011-03-16 00:00:00', $d->format('Y-m-d H:i:s')); + } + + /** + * Day of the month cannot accept a 0 value, it must be between 1 and 31 + * See Github issue #120 + * + * @since 2017-01-22 + */ + public function testDoesNotAccept0Date() + { + $f = new DayOfMonthField(); + $this->assertFalse($f->validate(0)); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfWeekFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfWeekFieldTest.php new file mode 100644 index 0000000000..74e63c28ce --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/DayOfWeekFieldTest.php @@ -0,0 +1,156 @@ + + */ +class DayOfWeekFieldTest extends TestCase +{ + /** + * @covers \Cron\DayOfWeekField::validate + */ + public function testValidatesField() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->validate('1')); + $this->assertTrue($f->validate('01')); + $this->assertTrue($f->validate('00')); + $this->assertTrue($f->validate('*')); + $this->assertFalse($f->validate('*/3,1,1-12')); + $this->assertTrue($f->validate('SUN-2')); + $this->assertFalse($f->validate('1.')); + } + + /** + * @covers \Cron\DayOfWeekField::isSatisfiedBy + */ + public function testChecksIfSatisfied() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '?')); + $this->assertTrue($f->isSatisfiedBy(new DateTimeImmutable(), '?')); + } + + /** + * @covers \Cron\DayOfWeekField::increment + */ + public function testIncrementsDate() + { + $d = new DateTime('2011-03-15 11:15:00'); + $f = new DayOfWeekField(); + $f->increment($d); + $this->assertSame('2011-03-16 00:00:00', $d->format('Y-m-d H:i:s')); + + $d = new DateTime('2011-03-15 11:15:00'); + $f->increment($d, true); + $this->assertSame('2011-03-14 23:59:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\DayOfWeekField::increment + */ + public function testIncrementsDateTimeImmutable() + { + $d = new DateTimeImmutable('2011-03-15 11:15:00'); + $f = new DayOfWeekField(); + $f->increment($d); + $this->assertSame('2011-03-16 00:00:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\DayOfWeekField::isSatisfiedBy + */ + public function testValidatesHashValueWeekday() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Weekday must be a value between 0 and 7. 12 given'); + + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '12#1')); + } + + /** + * @covers \Cron\DayOfWeekField::isSatisfiedBy + */ + public function testValidatesHashValueNth() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('There are never more than 5 or less than 1 of a given weekday in a month'); + + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '3#6')); + } + + /** + * @covers \Cron\DayOfWeekField::validate + */ + public function testValidateWeekendHash() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->validate('MON#1')); + $this->assertTrue($f->validate('TUE#2')); + $this->assertTrue($f->validate('WED#3')); + $this->assertTrue($f->validate('THU#4')); + $this->assertTrue($f->validate('FRI#5')); + $this->assertTrue($f->validate('SAT#1')); + $this->assertTrue($f->validate('SUN#3')); + $this->assertTrue($f->validate('MON#1,MON#3')); + } + + /** + * @covers \Cron\DayOfWeekField::isSatisfiedBy + */ + public function testHandlesZeroAndSevenDayOfTheWeekValues() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2011-09-04 00:00:00'), '0-2')); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2011-09-04 00:00:00'), '6-0')); + + $this->assertTrue($f->isSatisfiedBy(new DateTime('2014-04-20 00:00:00'), 'SUN')); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2014-04-20 00:00:00'), 'SUN#3')); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2014-04-20 00:00:00'), '0#3')); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2014-04-20 00:00:00'), '7#3')); + } + + /** + * @covers \Cron\DayOfWeekField::isSatisfiedBy + */ + public function testHandlesLastWeekdayOfTheMonth() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2018-12-28 00:00:00'), 'FRIL')); + $this->assertTrue($f->isSatisfiedBy(new DateTime('2018-12-28 00:00:00'), '5L')); + $this->assertFalse($f->isSatisfiedBy(new DateTime('2018-12-21 00:00:00'), 'FRIL')); + $this->assertFalse($f->isSatisfiedBy(new DateTime('2018-12-21 00:00:00'), '5L')); + } + + /** + * @see https://github.com/mtdowling/cron-expression/issues/47 + */ + public function testIssue47() { + $f = new DayOfWeekField(); + $this->assertFalse($f->validate('mon,')); + $this->assertFalse($f->validate('mon-')); + $this->assertFalse($f->validate('*/2,')); + $this->assertFalse($f->validate('-mon')); + $this->assertFalse($f->validate(',1')); + $this->assertFalse($f->validate('*-')); + $this->assertFalse($f->validate(',-')); + } + + /** + * @see https://github.com/laravel/framework/commit/07d160ac3cc9764d5b429734ffce4fa311385403 + */ + public function testLiteralsExpandProperly() + { + $f = new DayOfWeekField(); + $this->assertTrue($f->validate('MON-FRI')); + $this->assertSame([1,2,3,4,5], $f->getRangeForExpression('MON-FRI', 7)); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/FieldFactoryTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/FieldFactoryTest.php new file mode 100644 index 0000000000..e25d070751 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/FieldFactoryTest.php @@ -0,0 +1,43 @@ + + */ +class FieldFactoryTest extends TestCase +{ + /** + * @covers \Cron\FieldFactory::getField + */ + public function testRetrievesFieldInstances() + { + $mappings = array( + 0 => 'Cron\MinutesField', + 1 => 'Cron\HoursField', + 2 => 'Cron\DayOfMonthField', + 3 => 'Cron\MonthField', + 4 => 'Cron\DayOfWeekField', + ); + + $f = new FieldFactory(); + + foreach ($mappings as $position => $class) { + $this->assertSame($class, get_class($f->getField($position))); + } + } + + /** + * @covers \Cron\FieldFactory::getField + */ + public function testValidatesFieldPosition() + { + $this->expectException(\InvalidArgumentException::class); + + $f = new FieldFactory(); + $f->getField(-1); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/HoursFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/HoursFieldTest.php new file mode 100644 index 0000000000..1849f28bea --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/HoursFieldTest.php @@ -0,0 +1,99 @@ + + */ +class HoursFieldTest extends TestCase +{ + /** + * @covers \Cron\HoursField::validate + */ + public function testValidatesField() + { + $f = new HoursField(); + $this->assertTrue($f->validate('1')); + $this->assertTrue($f->validate('00')); + $this->assertTrue($f->validate('01')); + $this->assertTrue($f->validate('*')); + $this->assertFalse($f->validate('*/3,1,1-12')); + } + + /** + * @covers \Cron\HoursField::isSatisfiedBy + */ + public function testChecksIfSatisfied() + { + $f = new HoursField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '?')); + $this->assertTrue($f->isSatisfiedBy(new DateTimeImmutable(), '?')); + } + + /** + * @covers \Cron\HoursField::increment + */ + public function testIncrementsDate() + { + $d = new DateTime('2011-03-15 11:15:00'); + $f = new HoursField(); + $f->increment($d); + $this->assertSame('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s')); + + $d->setTime(11, 15, 0); + $f->increment($d, true); + $this->assertSame('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\HoursField::increment + */ + public function testIncrementsDateTimeImmutable() + { + $d = new DateTimeImmutable('2011-03-15 11:15:00'); + $f = new HoursField(); + $f->increment($d); + $this->assertSame('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\HoursField::increment + */ + public function testIncrementsDateWithThirtyMinuteOffsetTimezone() + { + $tz = date_default_timezone_get(); + date_default_timezone_set('America/St_Johns'); + $d = new DateTime('2011-03-15 11:15:00'); + $f = new HoursField(); + $f->increment($d); + $this->assertSame('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s')); + + $d->setTime(11, 15, 0); + $f->increment($d, true); + $this->assertSame('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s')); + date_default_timezone_set($tz); + } + + /** + * @covers \Cron\HoursField::increment + */ + public function testIncrementDateWithFifteenMinuteOffsetTimezone() + { + $tz = date_default_timezone_get(); + date_default_timezone_set('Asia/Kathmandu'); + $d = new DateTime('2011-03-15 11:15:00'); + $f = new HoursField(); + $f->increment($d); + $this->assertSame('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s')); + + $d->setTime(11, 15, 0); + $f->increment($d, true); + $this->assertSame('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s')); + date_default_timezone_set($tz); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/MinutesFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/MinutesFieldTest.php new file mode 100644 index 0000000000..41a536d684 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/MinutesFieldTest.php @@ -0,0 +1,73 @@ + + */ +class MinutesFieldTest extends TestCase +{ + /** + * @covers \Cron\MinutesField::validate + */ + public function testValidatesField() + { + $f = new MinutesField(); + $this->assertTrue($f->validate('1')); + $this->assertTrue($f->validate('*')); + $this->assertFalse($f->validate('*/3,1,1-12')); + } + + /** + * @covers \Cron\MinutesField::isSatisfiedBy + */ + public function testChecksIfSatisfied() + { + $f = new MinutesField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '?')); + $this->assertTrue($f->isSatisfiedBy(new DateTimeImmutable(), '?')); + } + + /** + * @covers \Cron\MinutesField::increment + */ + public function testIncrementsDate() + { + $d = new DateTime('2011-03-15 11:15:00'); + $f = new MinutesField(); + $f->increment($d); + $this->assertSame('2011-03-15 11:16:00', $d->format('Y-m-d H:i:s')); + $f->increment($d, true); + $this->assertSame('2011-03-15 11:15:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\MinutesField::increment + */ + public function testIncrementsDateTimeImmutable() + { + $d = new DateTimeImmutable('2011-03-15 11:15:00'); + $f = new MinutesField(); + $f->increment($d); + $this->assertSame('2011-03-15 11:16:00', $d->format('Y-m-d H:i:s')); + } + + /** + * Various bad syntaxes that are reported to work, but shouldn't. + * + * @author Chris Tankersley + * @since 2017-08-18 + */ + public function testBadSyntaxesShouldNotValidate() + { + $f = new MinutesField(); + $this->assertFalse($f->validate('*-1')); + $this->assertFalse($f->validate('1-2-3')); + $this->assertFalse($f->validate('-1')); + } +} diff --git a/lib/vendor/dragonmantank/cron-expression/tests/Cron/MonthFieldTest.php b/lib/vendor/dragonmantank/cron-expression/tests/Cron/MonthFieldTest.php new file mode 100644 index 0000000000..f329f4c161 --- /dev/null +++ b/lib/vendor/dragonmantank/cron-expression/tests/Cron/MonthFieldTest.php @@ -0,0 +1,103 @@ + + */ +class MonthFieldTest extends TestCase +{ + /** + * @covers \Cron\MonthField::validate + */ + public function testValidatesField() + { + $f = new MonthField(); + $this->assertTrue($f->validate('12')); + $this->assertTrue($f->validate('*')); + $this->assertFalse($f->validate('*/10,2,1-12')); + $this->assertFalse($f->validate('1.fix-regexp')); + } + + /** + * @covers \Cron\MonthField::isSatisfiedBy + */ + public function testChecksIfSatisfied() + { + $f = new MonthField(); + $this->assertTrue($f->isSatisfiedBy(new DateTime(), '?')); + $this->assertTrue($f->isSatisfiedBy(new DateTimeImmutable(), '?')); + } + + /** + * @covers \Cron\MonthField::increment + */ + public function testIncrementsDate() + { + $d = new DateTime('2011-03-15 11:15:00'); + $f = new MonthField(); + $f->increment($d); + $this->assertSame('2011-04-01 00:00:00', $d->format('Y-m-d H:i:s')); + + $d = new DateTime('2011-03-15 11:15:00'); + $f->increment($d, true); + $this->assertSame('2011-02-28 23:59:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\MonthField::increment + */ + public function testIncrementsDateTimeImmutable() + { + $d = new DateTimeImmutable('2011-03-15 11:15:00'); + $f = new MonthField(); + $f->increment($d); + $this->assertSame('2011-04-01 00:00:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\MonthField::increment + */ + public function testIncrementsDateWithThirtyMinuteTimezone() + { + $tz = date_default_timezone_get(); + date_default_timezone_set('America/St_Johns'); + $d = new DateTime('2011-03-31 11:59:59'); + $f = new MonthField(); + $f->increment($d); + $this->assertSame('2011-04-01 00:00:00', $d->format('Y-m-d H:i:s')); + + $d = new DateTime('2011-03-15 11:15:00'); + $f->increment($d, true); + $this->assertSame('2011-02-28 23:59:00', $d->format('Y-m-d H:i:s')); + date_default_timezone_set($tz); + } + + + /** + * @covers \Cron\MonthField::increment + */ + public function testIncrementsYearAsNeeded() + { + $f = new MonthField(); + $d = new DateTime('2011-12-15 00:00:00'); + $f->increment($d); + $this->assertSame('2012-01-01 00:00:00', $d->format('Y-m-d H:i:s')); + } + + /** + * @covers \Cron\MonthField::increment + */ + public function testDecrementsYearAsNeeded() + { + $f = new MonthField(); + $d = new DateTime('2011-01-15 00:00:00'); + $f->increment($d, true); + $this->assertSame('2010-12-31 23:59:00', $d->format('Y-m-d H:i:s')); + } +} diff --git a/lib/vendor/erusev/parsedown/LICENSE.txt b/lib/vendor/erusev/parsedown/LICENSE.txt new file mode 100644 index 0000000000..8e7c764d16 --- /dev/null +++ b/lib/vendor/erusev/parsedown/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2018 Emanuil Rusev, erusev.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/vendor/erusev/parsedown/Parsedown.php b/lib/vendor/erusev/parsedown/Parsedown.php new file mode 100644 index 0000000000..1b9d6d5bc2 --- /dev/null +++ b/lib/vendor/erusev/parsedown/Parsedown.php @@ -0,0 +1,1712 @@ +DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + function setSafeMode($safeMode) + { + $this->safeMode = (bool) $safeMode; + + return $this; + } + + protected $safeMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) + { + foreach ($this->BlockTypes[$marker] as $blockType) + { + $blockTypes []= $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) + { + $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); + + if (isset($Block)) + { + $Block['type'] = $blockType; + + if ( ! isset($Block['identified'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block'.$Type.'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block'.$Type.'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + /** + * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes + * Every HTML element may have a class attribute specified. + * The attribute, if specified, must have a value that is a set + * of space-separated tokens representing the various classes + * that the element belongs to. + * [...] + * The space characters, for the purposes of this specification, + * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), + * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and + * U+000D CARRIAGE RETURN (CR). + */ + $language = substr($matches[1], 0, strcspn($matches[1], " \t\n\f\r")); + + $class = 'language-'.$language; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + if($name === 'ol') + { + $listStart = stristr($matches[0], '.', true); + + if($listStart !== '1') + { + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (chop($Line['text'], $Line['text'][0]) === '') + { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + if (isset($alignments[$index])) + { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => 'text-align: '.$alignment.';', + ); + } + + $HeaderElements []= $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables=array()) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) + { + # check to see if the current inline type is nestable in the current context + + if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + continue; + } + + $Inline = $this->{'inline'.$inlineType}($Excerpt); + + if ( ! isset($Inline)) + { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) + { + continue; + } + + # sets a default inline position + + if ( ! isset($Inline['position'])) + { + $Inline['position'] = $markerPosition; + } + + # cause the new element to 'inherit' our non nestables + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + if ( ! isset($matches[2])) + { + $url = 'mailto:' . $url; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'strong'; + } + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'em'; + } + else + { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $Excerpt['text'][1], + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') + { + return; + } + + $Excerpt['text']= substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) + { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + { + $Element['text'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) + { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) + { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + protected function inlineStrikethrough($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) + { + $url = $matches[0][0]; + + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + + $markup = '<'.$Element['name']; + + if (isset($Element['attributes'])) + { + foreach ($Element['attributes'] as $name => $value) + { + if ($value === null) + { + continue; + } + + $markup .= ' '.$name.'="'.self::escape($value).'"'; + } + } + + $permitRawHtml = false; + + if (isset($Element['text'])) + { + $text = $Element['text']; + } + // very strongly consider an alternative if you're writing an + // extension + elseif (isset($Element['rawHtml'])) + { + $text = $Element['rawHtml']; + $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; + $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; + } + + if (isset($text)) + { + $markup .= '>'; + + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($text, $Element['nonNestables']); + } + elseif (!$permitRawHtml) + { + $markup .= self::escape($text, true); + } + else + { + $markup .= $text; + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (isset($safeUrlNameToAtt[$Element['name']])) + { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if ( ! empty($Element['attributes'])) + { + foreach ($Element['attributes'] as $att => $val) + { + # filter out badly parsed attribute + if ( ! preg_match($goodAttribute, $att)) + { + unset($Element['attributes'][$att]); + } + # dump onevent attribute + elseif (self::striAtStart($att, 'on')) + { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) + { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) + { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + + # + # Static Methods + # + + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) + { + return false; + } + else + { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) + { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'kbd', 'mark', + 'u', 'xm', 'sub', 'nobr', + 'sup', 'ruby', + 'var', 'span', + 'wbr', 'time', + ); +} diff --git a/lib/vendor/erusev/parsedown/README.md b/lib/vendor/erusev/parsedown/README.md new file mode 100644 index 0000000000..b5d9ed2ee3 --- /dev/null +++ b/lib/vendor/erusev/parsedown/README.md @@ -0,0 +1,86 @@ +> I also make [Caret](https://caret.io?ref=parsedown) - a Markdown editor for Mac and PC. + +## Parsedown + +[![Build Status](https://img.shields.io/travis/erusev/parsedown/master.svg?style=flat-square)](https://travis-ci.org/erusev/parsedown) + + +Better Markdown Parser in PHP + +[Demo](http://parsedown.org/demo) | +[Benchmarks](http://parsedown.org/speed) | +[Tests](http://parsedown.org/tests/) | +[Documentation](https://github.com/erusev/parsedown/wiki/) + +### Features + +* One File +* No Dependencies +* Super Fast +* Extensible +* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown) +* Tested in 5.3 to 7.1 and in HHVM +* [Markdown Extra extension](https://github.com/erusev/parsedown-extra) + +### Installation + +Include `Parsedown.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown). + +### Example + +``` php +$Parsedown = new Parsedown(); + +echo $Parsedown->text('Hello _Parsedown_!'); # prints:

Hello Parsedown!

+``` + +More examples in [the wiki](https://github.com/erusev/parsedown/wiki/) and in [this video tutorial](http://youtu.be/wYZBY8DEikI). + +### Security + +Parsedown is capable of escaping user-input within the HTML that it generates. Additionally Parsedown will apply sanitisation to additional scripting vectors (such as scripting link destinations) that are introduced by the markdown syntax itself. + +To tell Parsedown that it is processing untrusted user-input, use the following: +```php +$parsedown = new Parsedown; +$parsedown->setSafeMode(true); +``` + +If instead, you wish to allow HTML within untrusted user-input, but still want output to be free from XSS it is recommended that you make use of a HTML sanitiser that allows HTML tags to be whitelisted, like [HTML Purifier](http://htmlpurifier.org/). + +In both cases you should strongly consider employing defence-in-depth measures, like [deploying a Content-Security-Policy](https://scotthelme.co.uk/content-security-policy-an-introduction/) (a browser security feature) so that your page is likely to be safe even if an attacker finds a vulnerability in one of the first lines of defence above. + +#### Security of Parsedown Extensions + +Safe mode does not necessarily yield safe results when using extensions to Parsedown. Extensions should be evaluated on their own to determine their specific safety against XSS. + +### Escaping HTML +> ⚠️  **WARNING:** This method isn't safe from XSS! + +If you wish to escape HTML **in trusted input**, you can use the following: +```php +$parsedown = new Parsedown; +$parsedown->setMarkupEscaped(true); +``` + +Beware that this still allows users to insert unsafe scripting vectors, such as links like `[xss](javascript:alert%281%29)`. + +### Questions + +**How does Parsedown work?** + +It tries to read Markdown like a human. First, it looks at the lines. It’s interested in how the lines start. This helps it recognise blocks. It knows, for example, that if a line starts with a `-` then perhaps it belongs to a list. Once it recognises the blocks, it continues to the content. As it reads, it watches out for special characters. This helps it recognise inline elements (or inlines). + +We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages. + +**Is it compliant with CommonMark?** + +It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve. + +**Who uses it?** + +[Laravel Framework](https://laravel.com/), [Bolt CMS](http://bolt.cm/), [Grav CMS](http://getgrav.org/), [Herbie CMS](http://www.getherbie.org/), [Kirby CMS](http://getkirby.com/), [October CMS](http://octobercms.com/), [Pico CMS](http://picocms.org), [Statamic CMS](http://www.statamic.com/), [phpDocumentor](http://www.phpdoc.org/), [RaspberryPi.org](http://www.raspberrypi.org/), [Symfony demo](https://github.com/symfony/symfony-demo) and [more](https://packagist.org/packages/erusev/parsedown/dependents). + +**How can I help?** + +Use it, star it, share it and if you feel generous, [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2). diff --git a/lib/vendor/erusev/parsedown/composer.json b/lib/vendor/erusev/parsedown/composer.json new file mode 100644 index 0000000000..f8b40f8ce8 --- /dev/null +++ b/lib/vendor/erusev/parsedown/composer.json @@ -0,0 +1,33 @@ +{ + "name": "erusev/parsedown", + "description": "Parser for Markdown.", + "keywords": ["markdown", "parser"], + "homepage": "http://parsedown.org", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "require": { + "php": ">=5.3.0", + "ext-mbstring": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "autoload": { + "psr-0": {"Parsedown": ""} + }, + "autoload-dev": { + "psr-0": { + "TestParsedown": "test/", + "ParsedownTest": "test/", + "CommonMarkTest": "test/", + "CommonMarkTestWeak": "test/" + } + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/CREDITS b/lib/vendor/ezyang/htmlpurifier/CREDITS new file mode 100644 index 0000000000..7921b45af7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/CREDITS @@ -0,0 +1,9 @@ + +CREDITS + +Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks +to the DevNetwork Community for their help (see docs/ref-devnetwork.html for +more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake +for letting me package his fantastic XSS cheatsheet for a smoketest. + + vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/LICENSE b/lib/vendor/ezyang/htmlpurifier/LICENSE new file mode 100644 index 0000000000..8c88a20d45 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/README.md b/lib/vendor/ezyang/htmlpurifier/README.md new file mode 100644 index 0000000000..e6b7199c12 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/README.md @@ -0,0 +1,29 @@ +HTML Purifier [![Build Status](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml) +============= + +HTML Purifier is an HTML filtering solution that uses a unique combination +of robust whitelists and aggressive parsing to ensure that not only are +XSS attacks thwarted, but the resulting HTML is standards compliant. + +HTML Purifier is oriented towards richly formatted documents from +untrusted sources that require CSS and a full tag-set. This library can +be configured to accept a more restrictive set of tags, but it won't be +as efficient as more bare-bones parsers. It will, however, do the job +right, which may be more important. + +Places to go: + +* See INSTALL for a quick installation guide +* See docs/ for developer-oriented documentation, code examples and + an in-depth installation guide. +* See WYSIWYG for information on editors like TinyMCE and FCKeditor + +HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/) + +## Installation + +Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier). + +If you're using Composer to manage dependencies, you can use + + $ composer require ezyang/htmlpurifier diff --git a/lib/vendor/ezyang/htmlpurifier/VERSION b/lib/vendor/ezyang/htmlpurifier/VERSION new file mode 100644 index 0000000000..ef8ffbdd9b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/VERSION @@ -0,0 +1 @@ +4.18.0 \ No newline at end of file diff --git a/lib/vendor/ezyang/htmlpurifier/composer.json b/lib/vendor/ezyang/htmlpurifier/composer.json new file mode 100644 index 0000000000..7799d1d22d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/composer.json @@ -0,0 +1,45 @@ +{ + "name": "ezyang/htmlpurifier", + "description": "Standards compliant HTML filter written in PHP", + "type": "library", + "keywords": ["html"], + "homepage": "http://htmlpurifier.org/", + "license": "LGPL-2.1-or-later", + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "autoload": { + "psr-0": { "HTMLPurifier": "library/" }, + "files": ["library/HTMLPurifier.composer.php"], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-tidy": "Used for pretty-printing HTML" + }, + "config": { + "sort-packages": true + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/ezyang/simpletest.git", + "no-api": true + } + ] +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php new file mode 100644 index 0000000000..1960c399f8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php @@ -0,0 +1,11 @@ +purify($html, $config); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php new file mode 100644 index 0000000000..4c713a33af --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php @@ -0,0 +1,236 @@ + $attributes) { + $allowed_elements[$element] = true; + foreach ($attributes as $attribute => $x) { + $allowed_attributes["$element.$attribute"] = true; + } + } + $config->set('HTML.AllowedElements', $allowed_elements); + $config->set('HTML.AllowedAttributes', $allowed_attributes); + if ($allowed_protocols !== null) { + $config->set('URI.AllowedSchemes', $allowed_protocols); + } + $purifier = new HTMLPurifier($config); + return $purifier->purify($string); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php new file mode 100644 index 0000000000..39b1b65319 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php @@ -0,0 +1,11 @@ +config = HTMLPurifier_Config::create($config); + $this->strategy = new HTMLPurifier_Strategy_Core(); + } + + /** + * Adds a filter to process the output. First come first serve + * + * @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object + */ + public function addFilter($filter) + { + trigger_error( + 'HTMLPurifier->addFilter() is deprecated, use configuration directives' . + ' in the Filter namespace or Filter.Custom', + E_USER_WARNING + ); + $this->filters[] = $filter; + } + + /** + * Filters an HTML snippet/document to be XSS-free and standards-compliant. + * + * @param string $html String of HTML to purify + * @param HTMLPurifier_Config $config Config object for this operation, + * if omitted, defaults to the config object specified during this + * object's construction. The parameter can also be any type + * that HTMLPurifier_Config::create() supports. + * + * @return string Purified HTML + */ + public function purify($html, $config = null) + { + // :TODO: make the config merge in, instead of replace + $config = $config ? HTMLPurifier_Config::create($config) : $this->config; + + // implementation is partially environment dependant, partially + // configuration dependant + $lexer = HTMLPurifier_Lexer::create($config); + + $context = new HTMLPurifier_Context(); + + // setup HTML generator + $this->generator = new HTMLPurifier_Generator($config, $context); + $context->register('Generator', $this->generator); + + // set up global context variables + if ($config->get('Core.CollectErrors')) { + // may get moved out if other facilities use it + $language_factory = HTMLPurifier_LanguageFactory::instance(); + $language = $language_factory->create($config, $context); + $context->register('Locale', $language); + + $error_collector = new HTMLPurifier_ErrorCollector($context); + $context->register('ErrorCollector', $error_collector); + } + + // setup id_accumulator context, necessary due to the fact that + // AttrValidator can be called from many places + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + + $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); + + // setup filters + $filter_flags = $config->getBatch('Filter'); + $custom_filters = $filter_flags['Custom']; + unset($filter_flags['Custom']); + $filters = array(); + foreach ($filter_flags as $filter => $flag) { + if (!$flag) { + continue; + } + if (strpos($filter, '.') !== false) { + continue; + } + $class = "HTMLPurifier_Filter_$filter"; + $filters[] = new $class; + } + foreach ($custom_filters as $filter) { + // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat + $filters[] = $filter; + } + $filters = array_merge($filters, $this->filters); + // maybe prepare(), but later + + for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) { + $html = $filters[$i]->preFilter($html, $config, $context); + } + + // purified HTML + $html = + $this->generator->generateFromTokens( + // list of tokens + $this->strategy->execute( + // list of un-purified tokens + $lexer->tokenizeHTML( + // un-purified HTML + $html, + $config, + $context + ), + $config, + $context + ) + ); + + for ($i = $filter_size - 1; $i >= 0; $i--) { + $html = $filters[$i]->postFilter($html, $config, $context); + } + + $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context); + $this->context =& $context; + return $html; + } + + /** + * Filters an array of HTML snippets + * + * @param string[] $array_of_html Array of html snippets + * @param HTMLPurifier_Config $config Optional config object for this operation. + * See HTMLPurifier::purify() for more details. + * + * @return string[] Array of purified HTML + */ + public function purifyArray($array_of_html, $config = null) + { + $context_array = array(); + $array = array(); + foreach($array_of_html as $key=>$value){ + if (is_array($value)) { + $array[$key] = $this->purifyArray($value, $config); + } else { + $array[$key] = $this->purify($value, $config); + } + $context_array[$key] = $this->context; + } + $this->context = $context_array; + return $array; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + */ + public static function instance($prototype = null) + { + if (!self::$instance || $prototype) { + if ($prototype instanceof HTMLPurifier) { + self::$instance = $prototype; + } elseif ($prototype) { + self::$instance = new HTMLPurifier($prototype); + } else { + self::$instance = new HTMLPurifier(); + } + } + return self::$instance; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + * @note Backwards compatibility, see instance() + */ + public static function getInstance($prototype = null) + { + return HTMLPurifier::instance($prototype); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php new file mode 100644 index 0000000000..8a417d2462 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php @@ -0,0 +1,230 @@ +getHTMLDefinition(); + $parent = new HTMLPurifier_Token_Start($definition->info_parent); + $stack = array($parent->toNode()); + foreach ($tokens as $token) { + $token->skip = null; // [MUT] + $token->carryover = null; // [MUT] + if ($token instanceof HTMLPurifier_Token_End) { + $token->start = null; // [MUT] + $r = array_pop($stack); + //assert($r->name === $token->name); + //assert(empty($token->attr)); + $r->endCol = $token->col; + $r->endLine = $token->line; + $r->endArmor = $token->armor; + continue; + } + $node = $token->toNode(); + $stack[count($stack)-1]->children[] = $node; + if ($token instanceof HTMLPurifier_Token_Start) { + $stack[] = $node; + } + } + //assert(count($stack) == 1); + return $stack[0]; + } + + public static function flatten($node, $config, $context) { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingTokens = array(); + $tokens = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + list($start, $end) = $node->toTokenPair(); + if ($level > 0) { + $tokens[] = $start; + } + if ($end !== NULL) { + $closingTokens[$level][] = $end; + } + if ($node instanceof HTMLPurifier_Node_Element) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->children as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingTokens[$level])) { + while ($token = array_pop($closingTokens[$level])) { + $tokens[] = $token; + } + } + } while ($level > 0); + return $tokens; + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php new file mode 100644 index 0000000000..c7b17cf144 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php @@ -0,0 +1,148 @@ +doConstruct($attr_types, $modules); + } + + public function doConstruct($attr_types, $modules) + { + // load extensions from the modules + foreach ($modules as $module) { + foreach ($module->attr_collections as $coll_i => $coll) { + if (!isset($this->info[$coll_i])) { + $this->info[$coll_i] = array(); + } + foreach ($coll as $attr_i => $attr) { + if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { + // merge in includes + $this->info[$coll_i][$attr_i] = array_merge( + $this->info[$coll_i][$attr_i], + $attr + ); + continue; + } + $this->info[$coll_i][$attr_i] = $attr; + } + } + } + // perform internal expansions and inclusions + foreach ($this->info as $name => $attr) { + // merge attribute collections that include others + $this->performInclusions($this->info[$name]); + // replace string identifiers with actual attribute objects + $this->expandIdentifiers($this->info[$name], $attr_types); + } + } + + /** + * Takes a reference to an attribute associative array and performs + * all inclusions specified by the zero index. + * @param array &$attr Reference to attribute array + */ + public function performInclusions(&$attr) + { + if (!isset($attr[0])) { + return; + } + $merge = $attr[0]; + $seen = array(); // recursion guard + // loop through all the inclusions + for ($i = 0; isset($merge[$i]); $i++) { + if (isset($seen[$merge[$i]])) { + continue; + } + $seen[$merge[$i]] = true; + // foreach attribute of the inclusion, copy it over + if (!isset($this->info[$merge[$i]])) { + continue; + } + foreach ($this->info[$merge[$i]] as $key => $value) { + if (isset($attr[$key])) { + continue; + } // also catches more inclusions + $attr[$key] = $value; + } + if (isset($this->info[$merge[$i]][0])) { + // recursion + $merge = array_merge($merge, $this->info[$merge[$i]][0]); + } + } + unset($attr[0]); + } + + /** + * Expands all string identifiers in an attribute array by replacing + * them with the appropriate values inside HTMLPurifier_AttrTypes + * @param array &$attr Reference to attribute array + * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance + */ + public function expandIdentifiers(&$attr, $attr_types) + { + // because foreach will process new elements we add, make sure we + // skip duplicates + $processed = array(); + + foreach ($attr as $def_i => $def) { + // skip inclusions + if ($def_i === 0) { + continue; + } + + if (isset($processed[$def_i])) { + continue; + } + + // determine whether or not attribute is required + if ($required = (strpos($def_i, '*') !== false)) { + // rename the definition + unset($attr[$def_i]); + $def_i = trim($def_i, '*'); + $attr[$def_i] = $def; + } + + $processed[$def_i] = true; + + // if we've already got a literal object, move on + if (is_object($def)) { + // preserve previous required + $attr[$def_i]->required = ($required || $attr[$def_i]->required); + continue; + } + + if ($def === false) { + unset($attr[$def_i]); + continue; + } + + if ($t = $attr_types->get($def)) { + $attr[$def_i] = $t; + $attr[$def_i]->required = $required; + } else { + unset($attr[$def_i]); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php new file mode 100644 index 0000000000..739646fa7c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php @@ -0,0 +1,144 @@ + by removing + * leading and trailing whitespace, ignoring line feeds, and replacing + * carriage returns and tabs with spaces. While most useful for HTML + * attributes specified as CDATA, it can also be applied to most CSS + * values. + * + * @note This method is not entirely standards compliant, as trim() removes + * more types of whitespace than specified in the spec. In practice, + * this is rarely a problem, as those extra characters usually have + * already been removed by HTMLPurifier_Encoder. + * + * @warning This processing is inconsistent with XML's whitespace handling + * as specified by section 3.3.3 and referenced XHTML 1.0 section + * 4.7. However, note that we are NOT necessarily + * parsing XML, thus, this behavior may still be correct. We + * assume that newlines have been normalized. + */ + public function parseCDATA($string) + { + $string = trim($string); + $string = str_replace(array("\n", "\t", "\r"), ' ', $string); + return $string; + } + + /** + * Factory method for creating this class from a string. + * @param string $string String construction info + * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string + */ + public function make($string) + { + // default implementation, return a flyweight of this object. + // If $string has an effect on the returned object (i.e. you + // need to overload this method), it is best + // to clone or instantiate new copies. (Instantiation is safer.) + return $this; + } + + /** + * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work + * properly. THIS IS A HACK! + * @param string $string a CSS colour definition + * @return string + */ + protected function mungeRgb($string) + { + $p = '\s*(\d+(\.\d+)?([%]?))\s*'; + + if (preg_match('/(rgba|hsla)\(/', $string)) { + return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string); + } + + return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string); + } + + /** + * Parses a possibly escaped CSS string and returns the "pure" + * version of it. + */ + protected function expandCSSEscape($string) + { + // flexibly parse it + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] === '\\') { + $i++; + if ($i >= $c) { + $ret .= '\\'; + break; + } + if (ctype_xdigit($string[$i])) { + $code = $string[$i]; + for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { + if (!ctype_xdigit($string[$i])) { + break; + } + $code .= $string[$i]; + } + // We have to be extremely careful when adding + // new characters, to make sure we're not breaking + // the encoding. + $char = HTMLPurifier_Encoder::unichr(hexdec($code)); + if (HTMLPurifier_Encoder::cleanUTF8($char) === '') { + continue; + } + $ret .= $char; + if ($i < $c && trim($string[$i]) !== '') { + $i--; + } + continue; + } + if ($string[$i] === "\n") { + continue; + } + } + $ret .= $string[$i]; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php new file mode 100644 index 0000000000..af6b8a05d1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php @@ -0,0 +1,140 @@ +parseCDATA($css); + + $definition = $config->getCSSDefinition(); + $allow_duplicates = $config->get("CSS.AllowDuplicates"); + + $universal_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'initial', + 'inherit', + 'unset', + ) + ); + + // According to the CSS2.1 spec, the places where a + // non-delimiting semicolon can appear are in strings + // escape sequences. So here is some dumb hack to + // handle quotes. + $len = strlen($css); + $accum = ""; + $declarations = array(); + $quoted = false; + for ($i = 0; $i < $len; $i++) { + $c = strcspn($css, ";'\"", $i); + $accum .= substr($css, $i, $c); + $i += $c; + if ($i == $len) break; + $d = $css[$i]; + if ($quoted) { + $accum .= $d; + if ($d == $quoted) { + $quoted = false; + } + } else { + if ($d == ";") { + $declarations[] = $accum; + $accum = ""; + } else { + $accum .= $d; + $quoted = $d; + } + } + } + if ($accum != "") $declarations[] = $accum; + + $propvalues = array(); + $new_declarations = ''; + + /** + * Name of the current CSS property being validated. + */ + $property = false; + $context->register('CurrentCSSProperty', $property); + + foreach ($declarations as $declaration) { + if (!$declaration) { + continue; + } + if (!strpos($declaration, ':')) { + continue; + } + list($property, $value) = explode(':', $declaration, 2); + $property = trim($property); + $value = trim($value); + $ok = false; + do { + if (isset($definition->info[$property])) { + $ok = true; + break; + } + if (ctype_lower($property)) { + break; + } + $property = strtolower($property); + if (isset($definition->info[$property])) { + $ok = true; + break; + } + } while (0); + if (!$ok) { + continue; + } + $result = $universal_attrdef->validate($value, $config, $context); + if ($result === false) { + $result = $definition->info[$property]->validate( + $value, + $config, + $context + ); + } + if ($result === false) { + continue; + } + if ($allow_duplicates) { + $new_declarations .= "$property:$result;"; + } else { + $propvalues[$property] = $result; + } + } + + $context->destroy('CurrentCSSProperty'); + + // procedure does not write the new CSS simultaneously, so it's + // slightly inefficient, but it's the only way of getting rid of + // duplicates. Perhaps config to optimize it, but not now. + + foreach ($propvalues as $prop => $value) { + $new_declarations .= "$prop:$value;"; + } + + return $new_declarations ? $new_declarations : false; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 0000000000..af2b83dff8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php @@ -0,0 +1,34 @@ + 1.0) { + $result = '1'; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php new file mode 100644 index 0000000000..28c49883a7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php @@ -0,0 +1,113 @@ +getCSSDefinition(); + $this->info['background-color'] = $def->info['background-color']; + $this->info['background-image'] = $def->info['background-image']; + $this->info['background-repeat'] = $def->info['background-repeat']; + $this->info['background-attachment'] = $def->info['background-attachment']; + $this->info['background-position'] = $def->info['background-position']; + $this->info['background-size'] = $def->info['background-size']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // munge rgb() decl if necessary + $string = $this->mungeRgb($string); + + // assumes URI doesn't have spaces in it + $bits = explode(' ', $string); // bits to process + + $caught = array(); + $caught['color'] = false; + $caught['image'] = false; + $caught['repeat'] = false; + $caught['attachment'] = false; + $caught['position'] = false; + $caught['size'] = false; + + $i = 0; // number of catches + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($key != 'position') { + if ($status !== false) { + continue; + } + $r = $this->info['background-' . $key]->validate($bit, $config, $context); + } else { + $r = $bit; + } + if ($r === false) { + continue; + } + if ($key == 'position') { + if ($caught[$key] === false) { + $caught[$key] = ''; + } + $caught[$key] .= $r . ' '; + } else { + $caught[$key] = $r; + } + $i++; + break; + } + } + + if (!$i) { + return false; + } + if ($caught['position'] !== false) { + $caught['position'] = $this->info['background-position']-> + validate($caught['position'], $config, $context); + } + + $ret = array(); + foreach ($caught as $value) { + if ($value === false) { + continue; + } + $ret[] = $value; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php new file mode 100644 index 0000000000..4580ef5a91 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php @@ -0,0 +1,157 @@ + | | left | center | right + ] + [ + | | top | center | bottom + ]? + ] | + [ // this signifies that the vertical and horizontal adjectives + // can be arbitrarily ordered, however, there can only be two, + // one of each, or none at all + [ + left | center | right + ] || + [ + top | center | bottom + ] + ] + top, left = 0% + center, (none) = 50% + bottom, right = 100% +*/ + +/* QuirksMode says: + keyword + length/percentage must be ordered correctly, as per W3C + + Internet Explorer and Opera, however, support arbitrary ordering. We + should fix it up. + + Minor issue though, not strictly necessary. +*/ + +// control freaks may appreciate the ability to convert these to +// percentages or something, but it's not necessary + +/** + * Validates the value of background-position. + */ +class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef +{ + + /** + * @type HTMLPurifier_AttrDef_CSS_Length + */ + protected $length; + + /** + * @type HTMLPurifier_AttrDef_CSS_Percentage + */ + protected $percentage; + + public function __construct() + { + $this->length = new HTMLPurifier_AttrDef_CSS_Length(); + $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $bits = explode(' ', $string); + + $keywords = array(); + $keywords['h'] = false; // left, right + $keywords['v'] = false; // top, bottom + $keywords['ch'] = false; // center (first word) + $keywords['cv'] = false; // center (second word) + $measures = array(); + + $i = 0; + + $lookup = array( + 'top' => 'v', + 'bottom' => 'v', + 'left' => 'h', + 'right' => 'h', + 'center' => 'c' + ); + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + + // test for keyword + $lbit = ctype_lower($bit) ? $bit : strtolower($bit); + if (isset($lookup[$lbit])) { + $status = $lookup[$lbit]; + if ($status == 'c') { + if ($i == 0) { + $status = 'ch'; + } else { + $status = 'cv'; + } + } + $keywords[$status] = $lbit; + $i++; + } + + // test for length + $r = $this->length->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + + // test for percentage + $r = $this->percentage->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + } + + if (!$i) { + return false; + } // no valid values were caught + + $ret = array(); + + // first keyword + if ($keywords['h']) { + $ret[] = $keywords['h']; + } elseif ($keywords['ch']) { + $ret[] = $keywords['ch']; + $keywords['cv'] = false; // prevent re-use: center = center center + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if ($keywords['v']) { + $ret[] = $keywords['v']; + } elseif ($keywords['cv']) { + $ret[] = $keywords['cv']; + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php new file mode 100644 index 0000000000..16243ba1ed --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php @@ -0,0 +1,56 @@ +getCSSDefinition(); + $this->info['border-width'] = $def->info['border-width']; + $this->info['border-style'] = $def->info['border-style']; + $this->info['border-top-color'] = $def->info['border-top-color']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $string = $this->mungeRgb($string); + $bits = explode(' ', $string); + $done = array(); // segments we've finished + $ret = ''; // return value + foreach ($bits as $bit) { + foreach ($this->info as $propname => $validator) { + if (isset($done[$propname])) { + continue; + } + $r = $validator->validate($bit, $config, $context); + if ($r !== false) { + $ret .= $r . ' '; + $done[$propname] = true; + break; + } + } + } + return rtrim($ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php new file mode 100644 index 0000000000..d7287a00c2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php @@ -0,0 +1,161 @@ +alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param string $color + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($color, $config, $context) + { + static $colors = null; + if ($colors === null) { + $colors = $config->get('Core.ColorKeywords'); + } + + $color = trim($color); + if ($color === '') { + return false; + } + + $lower = strtolower($color); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + + if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) { + $length = strlen($color); + if (strpos($color, ')') !== $length - 1) { + return false; + } + + // get used function : rgb, rgba, hsl or hsla + $function = $matches[1]; + + $parameters_size = 3; + $alpha_channel = false; + if (substr($function, -1) === 'a') { + $parameters_size = 4; + $alpha_channel = true; + } + + /* + * Allowed types for values : + * parameter_position => [type => max_value] + */ + $allowed_types = array( + 1 => array('percentage' => 100, 'integer' => 255), + 2 => array('percentage' => 100, 'integer' => 255), + 3 => array('percentage' => 100, 'integer' => 255), + ); + $allow_different_types = false; + + if (strpos($function, 'hsl') !== false) { + $allowed_types = array( + 1 => array('integer' => 360), + 2 => array('percentage' => 100), + 3 => array('percentage' => 100), + ); + $allow_different_types = true; + } + + $values = trim(str_replace($function, '', $color), ' ()'); + + $parts = explode(',', $values); + if (count($parts) !== $parameters_size) { + return false; + } + + $type = false; + $new_parts = array(); + $i = 0; + + foreach ($parts as $part) { + $i++; + $part = trim($part); + + if ($part === '') { + return false; + } + + // different check for alpha channel + if ($alpha_channel === true && $i === count($parts)) { + $result = $this->alpha->validate($part, $config, $context); + + if ($result === false) { + return false; + } + + $new_parts[] = (string)$result; + continue; + } + + if (substr($part, -1) === '%') { + $current_type = 'percentage'; + } else { + $current_type = 'integer'; + } + + if (!array_key_exists($current_type, $allowed_types[$i])) { + return false; + } + + if (!$type) { + $type = $current_type; + } + + if ($allow_different_types === false && $type != $current_type) { + return false; + } + + $max_value = $allowed_types[$i][$current_type]; + + if ($current_type == 'integer') { + // Return value between range 0 -> $max_value + $new_parts[] = (int)max(min($part, $max_value), 0); + } elseif ($current_type == 'percentage') { + $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%'; + } + } + + $new_values = implode(',', $new_parts); + + $color = $function . '(' . $new_values . ')'; + } else { + // hexadecimal handling + if ($color[0] === '#') { + $hex = substr($color, 1); + } else { + $hex = $color; + $color = '#' . $color; + } + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + } + return $color; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php new file mode 100644 index 0000000000..9c1750554f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php @@ -0,0 +1,48 @@ +defs = $defs; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + foreach ($this->defs as $i => $def) { + $result = $this->defs[$i]->validate($string, $config, $context); + if ($result !== false) { + return $result; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php new file mode 100644 index 0000000000..9d77cc9aaf --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php @@ -0,0 +1,44 @@ +def = $def; + $this->element = $element; + } + + /** + * Checks if CurrentToken is set and equal to $this->element + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if ($token && $token->name == $this->element) { + return false; + } + return $this->def->validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 0000000000..bde4c3301f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php @@ -0,0 +1,77 @@ +intValidator = new HTMLPurifier_AttrDef_Integer(); + } + + /** + * @param string $value + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($value, $config, $context) + { + $value = $this->parseCDATA($value); + if ($value === 'none') { + return $value; + } + // if we looped this we could support multiple filters + $function_length = strcspn($value, '('); + $function = trim(substr($value, 0, $function_length)); + if ($function !== 'alpha' && + $function !== 'Alpha' && + $function !== 'progid:DXImageTransform.Microsoft.Alpha' + ) { + return false; + } + $cursor = $function_length + 1; + $parameters_length = strcspn($value, ')', $cursor); + $parameters = substr($value, $cursor, $parameters_length); + $params = explode(',', $parameters); + $ret_params = array(); + $lookup = array(); + foreach ($params as $param) { + list($key, $value) = explode('=', $param); + $key = trim($key); + $value = trim($value); + if (isset($lookup[$key])) { + continue; + } + if ($key !== 'opacity') { + continue; + } + $value = $this->intValidator->validate($value, $config, $context); + if ($value === false) { + continue; + } + $int = (int)$value; + if ($int > 100) { + $value = '100'; + } + if ($int < 0) { + $value = '0'; + } + $ret_params[] = "$key=$value"; + $lookup[$key] = true; + } + $ret_parameters = implode(',', $ret_params); + $ret_function = "$function($ret_parameters)"; + return $ret_function; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php new file mode 100644 index 0000000000..579b97ef1c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php @@ -0,0 +1,176 @@ +getCSSDefinition(); + $this->info['font-style'] = $def->info['font-style']; + $this->info['font-variant'] = $def->info['font-variant']; + $this->info['font-weight'] = $def->info['font-weight']; + $this->info['font-size'] = $def->info['font-size']; + $this->info['line-height'] = $def->info['line-height']; + $this->info['font-family'] = $def->info['font-family']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $system_fonts = array( + 'caption' => true, + 'icon' => true, + 'menu' => true, + 'message-box' => true, + 'small-caption' => true, + 'status-bar' => true + ); + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // check if it's one of the keywords + $lowercase_string = strtolower($string); + if (isset($system_fonts[$lowercase_string])) { + return $lowercase_string; + } + + $bits = explode(' ', $string); // bits to process + $stage = 0; // this indicates what we're looking for + $caught = array(); // which stage 0 properties have we caught? + $stage_1 = array('font-style', 'font-variant', 'font-weight'); + $final = ''; // output + + for ($i = 0, $size = count($bits); $i < $size; $i++) { + if ($bits[$i] === '') { + continue; + } + switch ($stage) { + case 0: // attempting to catch font-style, font-variant or font-weight + foreach ($stage_1 as $validator_name) { + if (isset($caught[$validator_name])) { + continue; + } + $r = $this->info[$validator_name]->validate( + $bits[$i], + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + $caught[$validator_name] = true; + break; + } + } + // all three caught, continue on + if (count($caught) >= 3) { + $stage = 1; + } + if ($r !== false) { + break; + } + case 1: // attempting to catch font-size and perhaps line-height + $found_slash = false; + if (strpos($bits[$i], '/') !== false) { + list($font_size, $line_height) = + explode('/', $bits[$i]); + if ($line_height === '') { + // ooh, there's a space after the slash! + $line_height = false; + $found_slash = true; + } + } else { + $font_size = $bits[$i]; + $line_height = false; + } + $r = $this->info['font-size']->validate( + $font_size, + $config, + $context + ); + if ($r !== false) { + $final .= $r; + // attempt to catch line-height + if ($line_height === false) { + // we need to scroll forward + for ($j = $i + 1; $j < $size; $j++) { + if ($bits[$j] === '') { + continue; + } + if ($bits[$j] === '/') { + if ($found_slash) { + return false; + } else { + $found_slash = true; + continue; + } + } + $line_height = $bits[$j]; + break; + } + } else { + // slash already found + $found_slash = true; + $j = $i; + } + if ($found_slash) { + $i = $j; + $r = $this->info['line-height']->validate( + $line_height, + $config, + $context + ); + if ($r !== false) { + $final .= '/' . $r; + } + } + $final .= ' '; + $stage = 2; + break; + } + return false; + case 2: // attempting to catch font-family + $font_family = + implode(' ', array_slice($bits, $i, $size - $i)); + $r = $this->info['font-family']->validate( + $font_family, + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + // processing completed successfully + return rtrim($final); + } + return false; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php new file mode 100644 index 0000000000..f1ff116361 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -0,0 +1,217 @@ +mask = array_reduce($c, function ($carry, $value) { + return $carry . $value; + }, '_- '); + + /* + PHP's internal strcspn implementation is + O(length of string * length of mask), making it inefficient + for large masks. However, it's still faster than + preg_match 8) + for (p = s1;;) { + spanp = s2; + do { + if (*spanp == c || p == s1_end) { + return p - s1; + } + } while (spanp++ < (s2_end - 1)); + c = *++p; + } + */ + // possible optimization: invert the mask. + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $generic_names = array( + 'serif' => true, + 'sans-serif' => true, + 'monospace' => true, + 'fantasy' => true, + 'cursive' => true + ); + $allowed_fonts = $config->get('CSS.AllowedFonts'); + + // assume that no font names contain commas in them + $fonts = explode(',', $string); + $final = ''; + foreach ($fonts as $font) { + $font = trim($font); + if ($font === '') { + continue; + } + // match a generic name + if (isset($generic_names[$font])) { + if ($allowed_fonts === null || isset($allowed_fonts[$font])) { + $final .= $font . ', '; + } + continue; + } + // match a quoted name + if ($font[0] === '"' || $font[0] === "'") { + $length = strlen($font); + if ($length <= 2) { + continue; + } + $quote = $font[0]; + if ($font[$length - 1] !== $quote) { + continue; + } + $font = substr($font, 1, $length - 2); + } + + $font = $this->expandCSSEscape($font); + + // $font is a pure representation of the font name + + if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { + continue; + } + + if (ctype_alnum($font) && $font !== '') { + // very simple font, allow it in unharmed + $final .= $font . ', '; + continue; + } + + // bugger out on whitespace. form feed (0C) really + // shouldn't show up regardless + $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); + + // Here, there are various classes of characters which need + // to be treated differently: + // - Alphanumeric characters are essentially safe. We + // handled these above. + // - Spaces require quoting, though most parsers will do + // the right thing if there aren't any characters that + // can be misinterpreted + // - Dashes rarely occur, but they fairly unproblematic + // for parsing/rendering purposes. + // The above characters cover the majority of Western font + // names. + // - Arbitrary Unicode characters not in ASCII. Because + // most parsers give little thought to Unicode, treatment + // of these codepoints is basically uniform, even for + // punctuation-like codepoints. These characters can + // show up in non-Western pages and are supported by most + // major browsers, for example: "MS 明朝" is a + // legitimate font-name + // . See + // the CSS3 spec for more examples: + // + // You can see live samples of these on the Internet: + // + // However, most of these fonts have ASCII equivalents: + // for example, 'MS Mincho', and it's considered + // professional to use ASCII font names instead of + // Unicode font names. Thanks Takeshi Terada for + // providing this information. + // The following characters, to my knowledge, have not been + // used to name font names. + // - Single quote. While theoretically you might find a + // font name that has a single quote in its name (serving + // as an apostrophe, e.g. Dave's Scribble), I haven't + // been able to find any actual examples of this. + // Internet Explorer's cssText translation (which I + // believe is invoked by innerHTML) normalizes any + // quoting to single quotes, and fails to escape single + // quotes. (Note that this is not IE's behavior for all + // CSS properties, just some sort of special casing for + // font-family). So a single quote *cannot* be used + // safely in the font-family context if there will be an + // innerHTML/cssText translation. Note that Firefox 3.x + // does this too. + // - Double quote. In IE, these get normalized to + // single-quotes, no matter what the encoding. (Fun + // fact, in IE8, the 'content' CSS property gained + // support, where they special cased to preserve encoded + // double quotes, but still translate unadorned double + // quotes into single quotes.) So, because their + // fixpoint behavior is identical to single quotes, they + // cannot be allowed either. Firefox 3.x displays + // single-quote style behavior. + // - Backslashes are reduced by one (so \\ -> \) every + // iteration, so they cannot be used safely. This shows + // up in IE7, IE8 and FF3 + // - Semicolons, commas and backticks are handled properly. + // - The rest of the ASCII punctuation is handled properly. + // We haven't checked what browsers do to unadorned + // versions, but this is not important as long as the + // browser doesn't /remove/ surrounding quotes (as IE does + // for HTML). + // + // With these results in hand, we conclude that there are + // various levels of safety: + // - Paranoid: alphanumeric, spaces and dashes(?) + // - International: Paranoid + non-ASCII Unicode + // - Edgy: Everything except quotes, backslashes + // - NoJS: Standards compliance, e.g. sod IE. Note that + // with some judicious character escaping (since certain + // types of escaping doesn't work) this is theoretically + // OK as long as innerHTML/cssText is not called. + // We believe that international is a reasonable default + // (that we will implement now), and once we do more + // extensive research, we may feel comfortable with dropping + // it down to edgy. + + // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of + // str(c)spn assumes that the string was already well formed + // Unicode (which of course it is). + if (strspn($font, $this->mask) !== strlen($font)) { + continue; + } + + // Historical: + // In the absence of innerHTML/cssText, these ugly + // transforms don't pose a security risk (as \\ and \" + // might--these escapes are not supported by most browsers). + // We could try to be clever and use single-quote wrapping + // when there is a double quote present, but I have choosen + // not to implement that. (NOTE: you can reduce the amount + // of escapes by one depending on what quoting style you use) + // $font = str_replace('\\', '\\5C ', $font); + // $font = str_replace('"', '\\22 ', $font); + // $font = str_replace("'", '\\27 ', $font); + + // font possibly with spaces, requires quoting + $final .= "'$font', "; + } + $final = rtrim($final, ', '); + if ($final === '') { + return false; + } + return $final; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php new file mode 100644 index 0000000000..973002c17f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php @@ -0,0 +1,32 @@ +def = $def; + $this->allow = $allow; + } + + /** + * Intercepts and removes !important if necessary + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // test for ! and important tokens + $string = trim($string); + $is_important = false; + // :TODO: optimization: test directly for !important and ! important + if (strlen($string) >= 9 && substr($string, -9) === 'important') { + $temp = rtrim(substr($string, 0, -9)); + // use a temp, because we might want to restore important + if (strlen($temp) >= 1 && substr($temp, -1) === '!') { + $string = rtrim(substr($temp, 0, -1)); + $is_important = true; + } + } + $string = $this->def->validate($string, $config, $context); + if ($this->allow && $is_important) { + $string .= ' !important'; + } + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php new file mode 100644 index 0000000000..f12453a04a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php @@ -0,0 +1,77 @@ +min = $min !== null ? HTMLPurifier_Length::make($min) : null; + $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + // Optimizations + if ($string === '') { + return false; + } + if ($string === '0') { + return '0'; + } + if (strlen($string) === 1) { + return false; + } + + $length = HTMLPurifier_Length::make($string); + if (!$length->isValid()) { + return false; + } + + if ($this->min) { + $c = $length->compareTo($this->min); + if ($c === false) { + return false; + } + if ($c < 0) { + return false; + } + } + if ($this->max) { + $c = $length->compareTo($this->max); + if ($c === false) { + return false; + } + if ($c > 0) { + return false; + } + } + return $length->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php new file mode 100644 index 0000000000..e74d42654e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php @@ -0,0 +1,112 @@ +getCSSDefinition(); + $this->info['list-style-type'] = $def->info['list-style-type']; + $this->info['list-style-position'] = $def->info['list-style-position']; + $this->info['list-style-image'] = $def->info['list-style-image']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // assumes URI doesn't have spaces in it + $bits = explode(' ', strtolower($string)); // bits to process + + $caught = array(); + $caught['type'] = false; + $caught['position'] = false; + $caught['image'] = false; + + $i = 0; // number of catches + $none = false; + + foreach ($bits as $bit) { + if ($i >= 3) { + return; + } // optimization bit + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($status !== false) { + continue; + } + $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); + if ($r === false) { + continue; + } + if ($r === 'none') { + if ($none) { + continue; + } else { + $none = true; + } + if ($key == 'image') { + continue; + } + } + $caught[$key] = $r; + $i++; + break; + } + } + + if (!$i) { + return false; + } + + $ret = array(); + + // construct type + if ($caught['type']) { + $ret[] = $caught['type']; + } + + // construct image + if ($caught['image']) { + $ret[] = $caught['image']; + } + + // construct position + if ($caught['position']) { + $ret[] = $caught['position']; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php new file mode 100644 index 0000000000..e707f871ca --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php @@ -0,0 +1,71 @@ +single = $single; + $this->max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->mungeRgb($this->parseCDATA($string)); + if ($string === '') { + return false; + } + $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n + $length = count($parts); + $final = ''; + for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { + if (ctype_space($parts[$i])) { + continue; + } + $result = $this->single->validate($parts[$i], $config, $context); + if ($result !== false) { + $final .= $result . ' '; + $num++; + } + } + if ($final === '') { + return false; + } + return rtrim($final); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php new file mode 100644 index 0000000000..ef49d20fdd --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php @@ -0,0 +1,90 @@ +non_negative = $non_negative; + } + + /** + * @param string $number + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string|bool + * @warning Some contexts do not pass $config, $context. These + * variables should not be used without checking HTMLPurifier_Length + */ + public function validate($number, $config, $context) + { + $number = $this->parseCDATA($number); + + if ($number === '') { + return false; + } + if ($number === '0') { + return '0'; + } + + $sign = ''; + switch ($number[0]) { + case '-': + if ($this->non_negative) { + return false; + } + $sign = '-'; + case '+': + $number = substr($number, 1); + } + + if (ctype_digit($number)) { + $number = ltrim($number, '0'); + return $number ? $sign . $number : '0'; + } + + // Period is the only non-numeric character allowed + if (strpos($number, '.') === false) { + return false; + } + + list($left, $right) = explode('.', $number, 2); + + if ($left === '' && $right === '') { + return false; + } + if ($left !== '' && !ctype_digit($left)) { + return false; + } + + // Remove leading zeros until positive number or a zero stays left + if (ltrim($left, '0') != '') { + $left = ltrim($left, '0'); + } else { + $left = '0'; + } + + $right = rtrim($right, '0'); + + if ($right === '') { + return $left ? $sign . $left : '0'; + } elseif (!ctype_digit($right)) { + return false; + } + return $sign . $left . '.' . $right; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php new file mode 100644 index 0000000000..f0f25c50a8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php @@ -0,0 +1,54 @@ +number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + if ($string === '') { + return false; + } + $length = strlen($string); + if ($length === 1) { + return false; + } + if ($string[$length - 1] !== '%') { + return false; + } + + $number = substr($string, 0, $length - 1); + $number = $this->number_def->validate($number, $config, $context); + + if ($number === false) { + return false; + } + return "$number%"; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ratio.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ratio.php new file mode 100644 index 0000000000..e08e2c496f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ratio.php @@ -0,0 +1,46 @@ +parseCDATA($ratio); + + $parts = explode('/', $ratio, 2); + $length = count($parts); + + if ($length < 1 || $length > 2) { + return false; + } + + $num = new \HTMLPurifier_AttrDef_CSS_Number(); + + if ($length === 1) { + return $num->validate($parts[0], $config, $context); + } + + $num1 = $num->validate($parts[0], $config, $context); + $num2 = $num->validate($parts[1], $config, $context); + + if ($num1 === false || $num2 === false) { + return false; + } + + return $num1 . '/' . $num2; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php new file mode 100644 index 0000000000..5fd4b7f7b4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php @@ -0,0 +1,46 @@ + true, + 'overline' => true, + 'underline' => true, + ); + + $string = strtolower($this->parseCDATA($string)); + + if ($string === 'none') { + return $string; + } + + $parts = explode(' ', $string); + $final = ''; + foreach ($parts as $part) { + if (isset($allowed_values[$part])) { + $final .= $part . ' '; + } + } + $final = rtrim($final); + if ($final === '') { + return false; + } + return $final; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php new file mode 100644 index 0000000000..6617acace5 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php @@ -0,0 +1,77 @@ +parseCDATA($uri_string); + if (strpos($uri_string, 'url(') !== 0) { + return false; + } + $uri_string = substr($uri_string, 4); + if (strlen($uri_string) == 0) { + return false; + } + $new_length = strlen($uri_string) - 1; + if ($uri_string[$new_length] != ')') { + return false; + } + $uri = trim(substr($uri_string, 0, $new_length)); + + if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { + $quote = $uri[0]; + $new_length = strlen($uri) - 1; + if ($uri[$new_length] !== $quote) { + return false; + } + $uri = substr($uri, 1, $new_length - 1); + } + + $uri = $this->expandCSSEscape($uri); + + $result = parent::validate($uri, $config, $context); + + if ($result === false) { + return false; + } + + // extra sanity check; should have been done by URI + $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); + + // suspicious characters are ()'; we're going to percent encode + // them for safety. + $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); + + // there's an extra bug where ampersands lose their escaping on + // an innerHTML cycle, so a very unlucky query parameter could + // then change the meaning of the URL. Unfortunately, there's + // not much we can do about that... + return "url(\"$result\")"; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php new file mode 100644 index 0000000000..6698a00c01 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php @@ -0,0 +1,44 @@ +clone = $clone; + } + + /** + * @param string $v + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($v, $config, $context) + { + return $this->clone->validate($v, $config, $context); + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + return clone $this->clone; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php new file mode 100644 index 0000000000..8abda7f6e2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php @@ -0,0 +1,73 @@ +valid_values = array_flip($valid_values); + $this->case_sensitive = $case_sensitive; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if (!$this->case_sensitive) { + // we may want to do full case-insensitive libraries + $string = ctype_lower($string) ? $string : strtolower($string); + } + $result = isset($this->valid_values[$string]); + + return $result ? $string : false; + } + + /** + * @param string $string In form of comma-delimited list of case-insensitive + * valid values. Example: "foo,bar,baz". Prepend "s:" to make + * case sensitive + * @return HTMLPurifier_AttrDef_Enum + */ + public function make($string) + { + if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { + $string = substr($string, 2); + $sensitive = true; + } else { + $sensitive = false; + } + $values = explode(',', $string); + return new HTMLPurifier_AttrDef_Enum($values, $sensitive); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php new file mode 100644 index 0000000000..be3bbc8dc0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php @@ -0,0 +1,48 @@ +name = $name; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + return $this->name; + } + + /** + * @param string $string Name of attribute + * @return HTMLPurifier_AttrDef_HTML_Bool + */ + public function make($string) + { + return new HTMLPurifier_AttrDef_HTML_Bool($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 0000000000..d5013488fc --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php @@ -0,0 +1,48 @@ +getDefinition('HTML')->doctype->name; + if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { + return parent::split($string, $config, $context); + } else { + return preg_split('/\s+/', $string); + } + } + + /** + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + $allowed = $config->get('Attr.AllowedClasses'); + $forbidden = $config->get('Attr.ForbiddenClasses'); + $ret = array(); + foreach ($tokens as $token) { + if (($allowed === null || isset($allowed[$token])) && + !isset($forbidden[$token]) && + // We need this O(n) check because of PHP's array + // implementation that casts -0 to 0. + !in_array($token, $ret, true) + ) { + $ret[] = $token; + } + } + return $ret; + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php new file mode 100644 index 0000000000..946ebb7820 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php @@ -0,0 +1,51 @@ +get('Core.ColorKeywords'); + } + + $string = trim($string); + + if (empty($string)) { + return false; + } + $lower = strtolower($string); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + if ($string[0] === '#') { + $hex = substr($string, 1); + } else { + $hex = $string; + } + + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + if ($length === 3) { + $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; + } + return "#$hex"; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php new file mode 100644 index 0000000000..5b03d3e378 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php @@ -0,0 +1,16 @@ +get('HTML.Trusted')) { + $allowed = array('', 'true', 'false'); + } + + $enum = new HTMLPurifier_AttrDef_Enum($allowed); + + return $enum->validate($string, $config, $context); + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php new file mode 100644 index 0000000000..d79ba12b3f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php @@ -0,0 +1,38 @@ +valid_values === false) { + $this->valid_values = $config->get('Attr.AllowedFrameTargets'); + } + return parent::validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php new file mode 100644 index 0000000000..4ba45610fe --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php @@ -0,0 +1,113 @@ +selector = $selector; + } + + /** + * @param string $id + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($id, $config, $context) + { + if (!$this->selector && !$config->get('Attr.EnableID')) { + return false; + } + + $id = trim($id); // trim it first + + if ($id === '') { + return false; + } + + $prefix = $config->get('Attr.IDPrefix'); + if ($prefix !== '') { + $prefix .= $config->get('Attr.IDPrefixLocal'); + // prevent re-appending the prefix + if (strpos($id, $prefix) !== 0) { + $id = $prefix . $id; + } + } elseif ($config->get('Attr.IDPrefixLocal') !== '') { + trigger_error( + '%Attr.IDPrefixLocal cannot be used unless ' . + '%Attr.IDPrefix is set', + E_USER_WARNING + ); + } + + if (!$this->selector) { + $id_accumulator =& $context->get('IDAccumulator'); + if (isset($id_accumulator->ids[$id])) { + return false; + } + } + + // we purposely avoid using regex, hopefully this is faster + + if ($config->get('Attr.ID.HTML5') === true) { + if (preg_match('/[\t\n\x0b\x0c ]/', $id)) { + return false; + } + } else { + if (ctype_alpha($id)) { + // OK + } else { + if (!ctype_alpha(@$id[0])) { + return false; + } + // primitive style of regexps, I suppose + $trim = trim( + $id, + 'A..Za..z0..9:-._' + ); + if ($trim !== '') { + return false; + } + } + } + + $regexp = $config->get('Attr.IDBlacklistRegexp'); + if ($regexp && preg_match($regexp, $id)) { + return false; + } + + if (!$this->selector) { + $id_accumulator->add($id); + } + + // if no change was made to the ID, return the result + // else, return the new id if stripping whitespace made it + // valid, or return false. + return $id; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php new file mode 100644 index 0000000000..1c4006fbbd --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php @@ -0,0 +1,56 @@ + 100) { + return '100%'; + } + return ((string)$points) . '%'; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 0000000000..63fa04c15c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -0,0 +1,72 @@ + 'AllowedRel', + 'rev' => 'AllowedRev' + ); + if (!isset($configLookup[$name])) { + trigger_error( + 'Unrecognized attribute name for link ' . + 'relationship.', + E_USER_ERROR + ); + return; + } + $this->name = $configLookup[$name]; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $allowed = $config->get('Attr.' . $this->name); + if (empty($allowed)) { + return false; + } + + $string = $this->parseCDATA($string); + $parts = explode(' ', $string); + + // lookup to prevent duplicates + $ret_lookup = array(); + foreach ($parts as $part) { + $part = strtolower(trim($part)); + if (!isset($allowed[$part])) { + continue; + } + $ret_lookup[$part] = true; + } + + if (empty($ret_lookup)) { + return false; + } + $string = implode(' ', array_keys($ret_lookup)); + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php new file mode 100644 index 0000000000..bbb20f2f80 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php @@ -0,0 +1,60 @@ +split($string, $config, $context); + $tokens = $this->filter($tokens, $config, $context); + if (empty($tokens)) { + return false; + } + return implode(' ', $tokens); + } + + /** + * Splits a space separated list of tokens into its constituent parts. + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function split($string, $config, $context) + { + // OPTIMIZABLE! + // do the preg_match, capture all subpatterns for reformulation + + // we don't support U+00A1 and up codepoints or + // escaping because I don't know how to do that with regexps + // and plus it would complicate optimization efforts (you never + // see that anyway). + $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start + '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' . + '(?:(?=\s)|\z)/'; // look ahead for space or string end + preg_match_all($pattern, $string, $matches); + return $matches[1]; + } + + /** + * Template method for removing certain tokens based on arbitrary criteria. + * @note If we wanted to be really functional, we'd do an array_filter + * with a callback. But... we're not. + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php new file mode 100644 index 0000000000..a1d019e095 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php @@ -0,0 +1,76 @@ +max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if ($string === '0') { + return $string; + } + if ($string === '') { + return false; + } + $length = strlen($string); + if (substr($string, $length - 2) == 'px') { + $string = substr($string, 0, $length - 2); + } + if (!is_numeric($string)) { + return false; + } + $int = (int)$string; + + if ($int < 0) { + return '0'; + } + + // upper-bound value, extremely high values can + // crash operating systems, see + // WARNING, above link WILL crash you if you're using Windows + + if ($this->max !== null && $int > $this->max) { + return (string)$this->max; + } + return (string)$int; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + if ($string === '') { + $max = null; + } else { + $max = (int)$string; + } + $class = get_class($this); + return new $class($max); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php new file mode 100644 index 0000000000..400e707d2f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php @@ -0,0 +1,91 @@ +negative = $negative; + $this->zero = $zero; + $this->positive = $positive; + } + + /** + * @param string $integer + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($integer, $config, $context) + { + $integer = $this->parseCDATA($integer); + if ($integer === '') { + return false; + } + + // we could possibly simply typecast it to integer, but there are + // certain fringe cases that must not return an integer. + + // clip leading sign + if ($this->negative && $integer[0] === '-') { + $digits = substr($integer, 1); + if ($digits === '0') { + $integer = '0'; + } // rm minus sign for zero + } elseif ($this->positive && $integer[0] === '+') { + $digits = $integer = substr($integer, 1); // rm unnecessary plus + } else { + $digits = $integer; + } + + // test if it's numeric + if (!ctype_digit($digits)) { + return false; + } + + // perform scope tests + if (!$this->zero && $integer == 0) { + return false; + } + if (!$this->positive && $integer > 0) { + return false; + } + if (!$this->negative && $integer < 0) { + return false; + } + + return $integer; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php new file mode 100644 index 0000000000..2a55cea642 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php @@ -0,0 +1,86 @@ + 8 || !ctype_alnum($subtags[1])) { + return $new_string; + } + if (!ctype_lower($subtags[1])) { + $subtags[1] = strtolower($subtags[1]); + } + + $new_string .= '-' . $subtags[1]; + if ($num_subtags == 2) { + return $new_string; + } + + // process all other subtags, index 2 and up + for ($i = 2; $i < $num_subtags; $i++) { + $length = strlen($subtags[$i]); + if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { + return $new_string; + } + if (!ctype_lower($subtags[$i])) { + $subtags[$i] = strtolower($subtags[$i]); + } + $new_string .= '-' . $subtags[$i]; + } + return $new_string; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php new file mode 100644 index 0000000000..c7eb3199a4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php @@ -0,0 +1,53 @@ +tag = $tag; + $this->withTag = $with_tag; + $this->withoutTag = $without_tag; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if (!$token || $token->name !== $this->tag) { + return $this->withoutTag->validate($string, $config, $context); + } else { + return $this->withTag->validate($string, $config, $context); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php new file mode 100644 index 0000000000..4553a4ea9b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php @@ -0,0 +1,21 @@ +parseCDATA($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php new file mode 100644 index 0000000000..c1cd89772c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php @@ -0,0 +1,111 @@ +parser = new HTMLPurifier_URIParser(); + $this->embedsResource = (bool)$embeds_resource; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef_URI + */ + public function make($string) + { + $embeds = ($string === 'embedded'); + return new HTMLPurifier_AttrDef_URI($embeds); + } + + /** + * @param string $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($uri, $config, $context) + { + if ($config->get('URI.Disable')) { + return false; + } + + $uri = $this->parseCDATA($uri); + + // parse the URI + $uri = $this->parser->parse($uri); + if ($uri === false) { + return false; + } + + // add embedded flag to context for validators + $context->register('EmbeddedURI', $this->embedsResource); + + $ok = false; + do { + + // generic validation + $result = $uri->validate($config, $context); + if (!$result) { + break; + } + + // chained filtering + $uri_def = $config->getDefinition('URI'); + $result = $uri_def->filter($uri, $config, $context); + if (!$result) { + break; + } + + // scheme-specific validation + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + break; + } + if ($this->embedsResource && !$scheme_obj->browsable) { + break; + } + $result = $scheme_obj->validate($uri, $config, $context); + if (!$result) { + break; + } + + // Post chained filtering + $result = $uri_def->postFilter($uri, $config, $context); + if (!$result) { + break; + } + + // survived gauntlet + $ok = true; + + } while (false); + + $context->destroy('EmbeddedURI'); + if (!$ok) { + return false; + } + // back to string + return $uri->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php new file mode 100644 index 0000000000..daf32b7643 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php @@ -0,0 +1,20 @@ +" + // that needs more percent encoding to be done + if ($string == '') { + return false; + } + $string = trim($string); + $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); + return $result ? $string : false; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php new file mode 100644 index 0000000000..17a97c1ecd --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php @@ -0,0 +1,136 @@ +ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); + $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $length = strlen($string); + // empty hostname is OK; it's usually semantically equivalent: + // the default host as defined by a URI scheme is used: + // + // If the URI scheme defines a default for host, then that + // default applies when the host subcomponent is undefined + // or when the registered name is empty (zero length). + if ($string === '') { + return ''; + } + if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') { + //IPv6 + $ip = substr($string, 1, $length - 2); + $valid = $this->ipv6->validate($ip, $config, $context); + if ($valid === false) { + return false; + } + return '[' . $valid . ']'; + } + + // need to do checks on unusual encodings too + $ipv4 = $this->ipv4->validate($string, $config, $context); + if ($ipv4 !== false) { + return $ipv4; + } + + // A regular domain name. + + // This doesn't match I18N domain names, but we don't have proper IRI support, + // so force users to insert Punycode. + + // Underscores defined as Unreserved Characters in RFC 3986 are + // allowed in a URI. There are cases where we want to consider a + // URI containing "_" such as "_dmarc.example.com". + // Underscores are not allowed in the default. If you want to + // allow it, set Core.AllowHostnameUnderscore to true. + $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; + + // Based off of RFC 1738, but amended so that + // as per RFC 3696, the top label need only not be all numeric. + // The productions describing this are: + $a = '[a-z]'; // alpha + $an = "[a-z0-9$underscore]"; // alphanum + $and = "[a-z0-9-$underscore]"; // alphanum | "-" + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + $domainlabel = "$an(?:$and*$an)?"; + // AMENDED as per RFC 3696 + // toplabel = alphanum | alphanum *( alphanum | "-" ) alphanum + // side condition: not all numeric + $toplabel = "$an(?:$and*$an)?"; + // hostname = *( domainlabel "." ) toplabel [ "." ] + if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) { + if (!ctype_digit($matches[1])) { + return $string; + } + } + + // PHP 5.3 and later support this functionality natively + if (function_exists('idn_to_ascii')) { + if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) { + $string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + } else { + $string = idn_to_ascii($string); + } + + // If we have Net_IDNA2 support, we can support IRIs by + // punycoding them. (This is the most portable thing to do, + // since otherwise we have to assume browsers support + } elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) { + $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); + // we need to encode each period separately + $parts = explode('.', $string); + try { + $new_parts = array(); + foreach ($parts as $part) { + $encodable = false; + for ($i = 0, $c = strlen($part); $i < $c; $i++) { + if (ord($part[$i]) > 0x7a) { + $encodable = true; + break; + } + } + if (!$encodable) { + $new_parts[] = $part; + } else { + $new_parts[] = $idna->encode($part); + } + } + $string = implode('.', $new_parts); + } catch (Exception $e) { + // XXX error reporting + } + } + // Try again + if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { + return $string; + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php new file mode 100644 index 0000000000..30ac16c9e7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php @@ -0,0 +1,45 @@ +ip4) { + $this->_loadRegex(); + } + + if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { + return $aIP; + } + return false; + } + + /** + * Lazy load function to prevent regex from being stuffed in + * cache. + */ + protected function _loadRegex() + { + $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 + $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php new file mode 100644 index 0000000000..f243793eeb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php @@ -0,0 +1,89 @@ +ip4) { + $this->_loadRegex(); + } + + $original = $aIP; + + $hex = '[0-9a-fA-F]'; + $blk = '(?:' . $hex . '{1,4})'; + $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 + + // prefix check + if (strpos($aIP, '/') !== false) { + if (preg_match('#' . $pre . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + unset($find); + } else { + return false; + } + } + + // IPv4-compatiblity check + if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + $ip = explode('.', $find[0]); + $ip = array_map('dechex', $ip); + $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; + unset($find, $ip); + } + + // compression check + $aIP = explode('::', $aIP); + $c = count($aIP); + if ($c > 2) { + return false; + } elseif ($c == 2) { + list($first, $second) = $aIP; + $first = explode(':', $first); + $second = explode(':', $second); + + if (count($first) + count($second) > 8) { + return false; + } + + while (count($first) < 8) { + array_push($first, '0'); + } + + array_splice($first, 8 - count($second), 8, $second); + $aIP = $first; + unset($first, $second); + } else { + $aIP = explode(':', $aIP[0]); + } + $c = count($aIP); + + if ($c != 8) { + return false; + } + + // All the pieces should be 16-bit hex strings. Are they? + foreach ($aIP as $piece) { + if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) { + return false; + } + } + return $original; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php new file mode 100644 index 0000000000..b428331f15 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php @@ -0,0 +1,60 @@ +confiscateAttr($attr, 'background'); + // some validation should happen here + + $this->prependCSS($attr, "background-image:url($background);"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php new file mode 100644 index 0000000000..d66c04a5b8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php @@ -0,0 +1,27 @@ +get('Attr.DefaultTextDir'); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php new file mode 100644 index 0000000000..0f51fd2cec --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php @@ -0,0 +1,28 @@ +confiscateAttr($attr, 'bgcolor'); + // some validation should happen here + + $this->prependCSS($attr, "background-color:$bgcolor;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php new file mode 100644 index 0000000000..f25cd01955 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php @@ -0,0 +1,47 @@ +attr = $attr; + $this->css = $css; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + unset($attr[$this->attr]); + $this->prependCSS($attr, $this->css); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php new file mode 100644 index 0000000000..057dc017fa --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php @@ -0,0 +1,26 @@ +confiscateAttr($attr, 'border'); + // some validation should happen here + $this->prependCSS($attr, "border:{$border_width}px solid;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php new file mode 100644 index 0000000000..7ccd0e3fb7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php @@ -0,0 +1,68 @@ +attr = $attr; + $this->enumToCSS = $enum_to_css; + $this->caseSensitive = (bool)$case_sensitive; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $value = trim($attr[$this->attr]); + unset($attr[$this->attr]); + + if (!$this->caseSensitive) { + $value = strtolower($value); + } + + if (!isset($this->enumToCSS[$value])) { + return $attr; + } + $this->prependCSS($attr, $this->enumToCSS[$value]); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php new file mode 100644 index 0000000000..235ebb34b6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php @@ -0,0 +1,47 @@ +get('Core.RemoveInvalidImg')) { + return $attr; + } + $attr['src'] = $config->get('Attr.DefaultInvalidImage'); + $src = false; + } + + if (!isset($attr['alt'])) { + if ($src) { + $alt = $config->get('Attr.DefaultImageAlt'); + if ($alt === null) { + $attr['alt'] = basename($attr['src']); + } else { + $attr['alt'] = $alt; + } + } else { + $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php new file mode 100644 index 0000000000..350b3358fc --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php @@ -0,0 +1,61 @@ + array('left', 'right'), + 'vspace' => array('top', 'bottom') + ); + + /** + * @param string $attr + */ + public function __construct($attr) + { + $this->attr = $attr; + if (!isset($this->css[$attr])) { + trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); + } + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $width = $this->confiscateAttr($attr, $this->attr); + // some validation could happen here + + if (!isset($this->css[$this->attr])) { + return $attr; + } + + $style = ''; + foreach ($this->css[$this->attr] as $suffix) { + $property = "margin-$suffix"; + $style .= "$property:{$width}px;"; + } + $this->prependCSS($attr, $style); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php new file mode 100644 index 0000000000..3ab47ed8c9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php @@ -0,0 +1,56 @@ +pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $t = 'text'; + } else { + $t = strtolower($attr['type']); + } + if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { + unset($attr['checked']); + } + if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { + unset($attr['maxlength']); + } + if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { + $result = $this->pixels->validate($attr['size'], $config, $context); + if ($result === false) { + unset($attr['size']); + } else { + $attr['size'] = $result; + } + } + if (isset($attr['src']) && $t !== 'image') { + unset($attr['src']); + } + if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { + $attr['value'] = ''; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php new file mode 100644 index 0000000000..5b0aff0e40 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php @@ -0,0 +1,31 @@ +name = $name; + $this->cssName = $css_name ? $css_name : $name; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->name])) { + return $attr; + } + $length = $this->confiscateAttr($attr, $this->name); + if (ctype_digit($length)) { + $length .= 'px'; + } + $this->prependCSS($attr, $this->cssName . ":$length;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php new file mode 100644 index 0000000000..63cce6837a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php @@ -0,0 +1,33 @@ +get('HTML.Attr.Name.UseCDATA')) { + return $attr; + } + if (!isset($attr['name'])) { + return $attr; + } + $id = $this->confiscateAttr($attr, 'name'); + if (isset($attr['id'])) { + return $attr; + } + $attr['id'] = $id; + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php new file mode 100644 index 0000000000..5a1fdbbfcc --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php @@ -0,0 +1,46 @@ +idDef = new HTMLPurifier_AttrDef_HTML_ID(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['name'])) { + return $attr; + } + $name = $attr['name']; + if (isset($attr['id']) && $attr['id'] === $name) { + return $attr; + } + $result = $this->idDef->validate($name, $config, $context); + if ($result === false) { + unset($attr['name']); + } else { + $attr['name'] = $result; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php new file mode 100644 index 0000000000..1057ebee1b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php @@ -0,0 +1,52 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + $scheme = $url->getSchemeObj($config, $context); + + if ($scheme->browsable && !$url->isLocal($config, $context)) { + if (isset($attr['rel'])) { + $rels = explode(' ', $attr['rel']); + if (!in_array('nofollow', $rels)) { + $rels[] = 'nofollow'; + } + $attr['rel'] = implode(' ', $rels); + } else { + $attr['rel'] = 'nofollow'; + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php new file mode 100644 index 0000000000..231c81a3f0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php @@ -0,0 +1,25 @@ +uri = new HTMLPurifier_AttrDef_URI(true); // embedded + $this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent')); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // If we add support for other objects, we'll need to alter the + // transforms. + switch ($attr['name']) { + // application/x-shockwave-flash + // Keep this synchronized with Injector/SafeObject.php + case 'allowScriptAccess': + $attr['value'] = 'never'; + break; + case 'allowNetworking': + $attr['value'] = 'internal'; + break; + case 'allowFullScreen': + if ($config->get('HTML.FlashAllowFullScreen')) { + $attr['value'] = ($attr['value'] == 'true') ? 'true' : 'false'; + } else { + $attr['value'] = 'false'; + } + break; + case 'wmode': + $attr['value'] = $this->wmode->validate($attr['value'], $config, $context); + break; + case 'movie': + case 'src': + $attr['name'] = "movie"; + $attr['value'] = $this->uri->validate($attr['value'], $config, $context); + break; + case 'flashvars': + // we're going to allow arbitrary inputs to the SWF, on + // the reasoning that it could only hack the SWF, not us. + break; + // add other cases to support other param name/value pairs + default: + $attr['name'] = $attr['value'] = null; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php new file mode 100644 index 0000000000..b7057bbf8e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php @@ -0,0 +1,23 @@ + + */ +class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $attr['type'] = 'text/javascript'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php new file mode 100644 index 0000000000..cc30ab8c38 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php @@ -0,0 +1,49 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + + // Ignore invalid schemes (e.g. `javascript:`) + if (!($scheme = $url->getSchemeObj($config, $context))) { + return $attr; + } + + if ($scheme->browsable && !$url->isBenign($config, $context)) { + $attr['target'] = '_blank'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php new file mode 100644 index 0000000000..1db3c6c09e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php @@ -0,0 +1,37 @@ + + */ +class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // Calculated from Firefox + if (!isset($attr['cols'])) { + $attr['cols'] = '22'; + } + if (!isset($attr['rows'])) { + $attr['rows'] = '3'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php new file mode 100644 index 0000000000..e4429e86d8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php @@ -0,0 +1,97 @@ +info['Enum'] = new HTMLPurifier_AttrDef_Enum(); + $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); + + $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); + $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); + $this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength(); + $this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens(); + $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); + $this->info['Text'] = new HTMLPurifier_AttrDef_Text(); + $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); + $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); + $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); + $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); + $this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); + $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); + $this->info['ContentEditable'] = new HTMLPurifier_AttrDef_HTML_ContentEditable(); + + // unimplemented aliases + $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Character'] = new HTMLPurifier_AttrDef_Text(); + + // "proprietary" types + $this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); + + // number is really a positive integer (one or more digits) + // FIXME: ^^ not always, see start and value of list items + $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); + } + + private static function makeEnum($in) + { + return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); + } + + /** + * Retrieves a type + * @param string $type String type name + * @return HTMLPurifier_AttrDef Object AttrDef for type + */ + public function get($type) + { + // determine if there is any extra info tacked on + if (strpos($type, '#') !== false) { + list($type, $string) = explode('#', $type, 2); + } else { + $string = ''; + } + + if (!isset($this->info[$type])) { + trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); + return; + } + return $this->info[$type]->make($string); + } + + /** + * Sets a new implementation for a type + * @param string $type String type name + * @param HTMLPurifier_AttrDef $impl Object AttrDef for type + */ + public function set($type, $impl) + { + $this->info[$type] = $impl; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php new file mode 100644 index 0000000000..f97dc93edd --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php @@ -0,0 +1,178 @@ +getHTMLDefinition(); + $e =& $context->get('ErrorCollector', true); + + // initialize IDAccumulator if necessary + $ok =& $context->get('IDAccumulator', true); + if (!$ok) { + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + } + + // initialize CurrentToken if necessary + $current_token =& $context->get('CurrentToken', true); + if (!$current_token) { + $context->register('CurrentToken', $token); + } + + if (!$token instanceof HTMLPurifier_Token_Start && + !$token instanceof HTMLPurifier_Token_Empty + ) { + return; + } + + // create alias to global definition array, see also $defs + // DEFINITION CALL + $d_defs = $definition->info_global_attr; + + // don't update token until the very end, to ensure an atomic update + $attr = $token->attr; + + // do global transformations (pre) + // nothing currently utilizes this + foreach ($definition->info_attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // do local transformations only applicable to this element (pre) + // ex.

to

+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // create alias to this element's attribute definition array, see + // also $d_defs (global attribute definition array) + // DEFINITION CALL + $defs = $definition->info[$token->name]->attr; + + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + + // iterate through all the attribute keypairs + // Watch out for name collisions: $key has previously been used + foreach ($attr as $attr_key => $value) { + + // call the definition + if (isset($defs[$attr_key])) { + // there is a local definition defined + if ($defs[$attr_key] === false) { + // We've explicitly been told not to allow this element. + // This is usually when there's a global definition + // that must be overridden. + // Theoretically speaking, we could have a + // AttrDef_DenyAll, but this is faster! + $result = false; + } else { + // validate according to the element's definition + $result = $defs[$attr_key]->validate( + $value, + $config, + $context + ); + } + } elseif (isset($d_defs[$attr_key])) { + // there is a global definition defined, validate according + // to the global definition + $result = $d_defs[$attr_key]->validate( + $value, + $config, + $context + ); + } else { + // system never heard of the attribute? DELETE! + $result = false; + } + + // put the results into effect + if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) { + $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + } + + // remove the attribute + unset($attr[$attr_key]); + } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + + // simple substitution + $attr[$attr_key] = $result; + } else { + // nothing happens + } + + // we'd also want slightly more complicated substitution + // involving an array as the return value, + // although we're not sure how colliding attributes would + // resolve (certain ones would be completely overriden, + // others would prepend themselves). + } + + $context->destroy('CurrentAttr'); + + // post transforms + + // global (error reporting untested) + foreach ($definition->info_attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // local (error reporting untested) + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + $token->attr = $attr; + + // destroy CurrentToken if we made it ourselves + if (!$current_token) { + $context->destroy('CurrentToken'); + } + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php new file mode 100644 index 0000000000..bd8f9984f8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php @@ -0,0 +1,91 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param string $class Class to load + * @return bool + */ + public static function autoload($class) + { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) { + return false; + } + // Technically speaking, it should be ok and more efficient to + // just do 'require', but Antonio Parraga reports that with + // Zend extensions such as Zend debugger and APC, this invariant + // may be broken. Since we have efficient alternatives, pay + // the cost here and avoid the bug. + require_once HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + * @param string $class Class path to get + * @return string + */ + public static function getPath($class) + { + if (strncmp('HTMLPurifier', $class, 12) !== 0) { + return false; + } + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) { + return false; + } + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() + { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if (spl_autoload_functions() === false) { + spl_autoload_register($autoload); + } else { + // prepend flag exists, no need for shenanigans + spl_autoload_register($autoload, true, true); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php new file mode 100644 index 0000000000..3732c076a6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php @@ -0,0 +1,565 @@ +info['text-align'] = new HTMLPurifier_AttrDef_Enum( + ['left', 'right', 'center', 'justify'], + false + ); + + $border_style = + $this->info['border-bottom-style'] = + $this->info['border-right-style'] = + $this->info['border-left-style'] = + $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( + [ + 'none', + 'hidden', + 'dotted', + 'dashed', + 'solid', + 'double', + 'groove', + 'ridge', + 'inset', + 'outset' + ], + false + ); + + $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); + + $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'left', 'right', 'both'], + false + ); + $this->info['float'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'left', 'right'], + false + ); + $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( + ['normal', 'italic', 'oblique'], + false + ); + $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( + ['normal', 'small-caps'], + false + ); + + $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['none']), + new HTMLPurifier_AttrDef_CSS_URI() + ] + ); + + $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( + ['inside', 'outside'], + false + ); + $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( + [ + 'disc', + 'circle', + 'square', + 'decimal', + 'lower-roman', + 'upper-roman', + 'lower-alpha', + 'upper-alpha', + 'none' + ], + false + ); + $this->info['list-style-image'] = $uri_or_none; + + $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); + + $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( + ['capitalize', 'uppercase', 'lowercase', 'none'], + false + ); + $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['background-image'] = $uri_or_none; + $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( + ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'] + ); + $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( + ['scroll', 'fixed'] + ); + $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + + $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'auto', + 'cover', + 'contain', + ] + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $border_color = + $this->info['border-top-color'] = + $this->info['border-bottom-color'] = + $this->info['border-left-color'] = + $this->info['border-right-color'] = + $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['transparent']), + new HTMLPurifier_AttrDef_CSS_Color() + ] + ); + + $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); + + $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); + + $border_width = + $this->info['border-top-width'] = + $this->info['border-bottom-width'] = + $this->info['border-left-width'] = + $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['thin', 'medium', 'thick']), + new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative + ] + ); + + $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); + + $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + 'larger', + 'smaller' + ] + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ] + ); + + $margin = + $this->info['margin-top'] = + $this->info['margin-bottom'] = + $this->info['margin-left'] = + $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto']) + ] + ); + + $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); + + // non-negative + $padding = + $this->info['padding-top'] = + $this->info['padding-bottom'] = + $this->info['padding-left'] = + $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ] + ); + + $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); + + $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ] + ); + + $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(['auto']) + ] + ); + $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + ] + ); + $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(['none']) + ] + ); + $max = $config->get('CSS.MaxImgLength'); + + $this->info['width'] = + $this->info['height'] = + $max === null ? + $trusted_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(['auto']) + ] + ), + // For everyone else: + $trusted_wh + ); + $this->info['min-width'] = + $this->info['min-height'] = + $max === null ? + $trusted_min_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + // For everyone else: + $trusted_min_wh + ); + $this->info['max-width'] = + $this->info['max-height'] = + $max === null ? + $trusted_max_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(['none']) + ] + ), + // For everyone else: + $trusted_max_wh + ); + + $this->info['aspect-ratio'] = new HTMLPurifier_AttrDef_CSS_Multiple( + new HTMLPurifier_AttrDef_CSS_Composite([ + new HTMLPurifier_AttrDef_CSS_Ratio(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ]) + ); + + // text-decoration and related shorthands + $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + + $this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'underline', 'overline', 'line-through'] + ); + + $this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum( + ['solid', 'double', 'dotted', 'dashed', 'wavy'] + ); + + $this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto', 'from-font']) + ]); + + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); + + // this could use specialized code + $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( + [ + 'normal', + 'bold', + 'bolder', + 'lighter', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900' + ], + false + ); + + // MUST be called after other font properties, as it references + // a CSSDefinition object + $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); + + // same here + $this->info['border'] = + $this->info['border-bottom'] = + $this->info['border-top'] = + $this->info['border-left'] = + $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); + + $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( + ['collapse', 'separate'] + ); + + $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( + ['top', 'bottom'] + ); + + $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( + ['auto', 'fixed'] + ); + + $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'baseline', + 'sub', + 'super', + 'top', + 'text-top', + 'middle', + 'bottom', + 'text-bottom' + ] + ), + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ] + ); + + $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); + + // These CSS properties don't work on many browsers, but we live + // in THE FUTURE! + $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( + ['nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line'] + ); + + if ($config->get('CSS.Proprietary')) { + $this->doSetupProprietary($config); + } + + if ($config->get('CSS.AllowTricky')) { + $this->doSetupTricky($config); + } + + if ($config->get('CSS.Trusted')) { + $this->doSetupTrusted($config); + } + + $allow_important = $config->get('CSS.AllowImportant'); + // wrap all attr-defs with decorator that handles !important + foreach ($this->info as $k => $v) { + $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); + } + + $this->setupConfigStuff($config); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupProprietary($config) + { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // vendor specific prefixes of opacity + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + + // more CSS3 + $this->info['page-break-after'] = + $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( + [ + 'auto', + 'always', + 'avoid', + 'left', + 'right' + ] + ); + $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(['auto', 'avoid']); + + $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative + new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative + ]); + + $this->info['border-top-left-radius'] = + $this->info['border-top-right-radius'] = + $this->info['border-bottom-right-radius'] = + $this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2); + // TODO: support SLASH syntax + $this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4); + + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTricky($config) + { + $this->info['display'] = new HTMLPurifier_AttrDef_Enum( + [ + 'inline', + 'block', + 'list-item', + 'run-in', + 'compact', + 'marker', + 'table', + 'inline-block', + 'inline-table', + 'table-row-group', + 'table-header-group', + 'table-footer-group', + 'table-row', + 'table-column-group', + 'table-column', + 'table-cell', + 'table-caption', + 'none' + ] + ); + $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( + ['visible', 'hidden', 'collapse'] + ); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(['visible', 'hidden', 'auto', 'scroll']); + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTrusted($config) + { + $this->info['position'] = new HTMLPurifier_AttrDef_Enum( + ['static', 'relative', 'absolute', 'fixed'] + ); + $this->info['top'] = + $this->info['left'] = + $this->info['right'] = + $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ] + ); + $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Integer(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ] + ); + } + + /** + * Performs extra config-based processing. Based off of + * HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_Config $config + * @todo Refactor duplicate elements into common class (probably using + * composition, not inheritance). + */ + protected function setupConfigStuff($config) + { + // setup allowed elements + $support = "(for information on implementing this, see the " . + "support forums) "; + $allowed_properties = $config->get('CSS.AllowedProperties'); + if ($allowed_properties !== null) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_properties[$name])) { + unset($this->info[$name]); + } + unset($allowed_properties[$name]); + } + // emit errors + foreach ($allowed_properties as $name => $d) { + // :TODO: Is this htmlspecialchars() call really necessary? + $name = htmlspecialchars($name); + trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); + } + } + + $forbidden_properties = $config->get('CSS.ForbiddenProperties'); + if ($forbidden_properties !== null) { + foreach ($this->info as $name => $d) { + if (isset($forbidden_properties[$name])) { + unset($this->info[$name]); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php new file mode 100644 index 0000000000..8eb17b82e1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php @@ -0,0 +1,52 @@ +elements; + } + + /** + * Validates nodes according to definition and returns modification. + * + * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node + * @param HTMLPurifier_Config $config HTMLPurifier_Config object + * @param HTMLPurifier_Context $context HTMLPurifier_Context object + * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children + */ + abstract public function validateChildren($children, $config, $context); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php new file mode 100644 index 0000000000..7439be26b6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php @@ -0,0 +1,67 @@ +inline = new HTMLPurifier_ChildDef_Optional($inline); + $this->block = new HTMLPurifier_ChildDef_Optional($block); + $this->elements = $this->block->elements; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + if ($context->get('IsInline') === false) { + return $this->block->validateChildren( + $children, + $config, + $context + ); + } else { + return $this->inline->validateChildren( + $children, + $config, + $context + ); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php new file mode 100644 index 0000000000..f515888a1d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php @@ -0,0 +1,102 @@ +dtd_regex = $dtd_regex; + $this->_compileRegex(); + } + + /** + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) + */ + protected function _compileRegex() + { + $raw = str_replace(' ', '', $this->dtd_regex); + if ($raw[0] != '(') { + $raw = "($raw)"; + } + $el = '[#a-zA-Z0-9_.-]+'; + $reg = $raw; + + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M + // DOING! Seriously: if there's problems, please report them. + + // collect all elements into the $elements array + preg_match_all("/$el/", $reg, $matches); + foreach ($matches[0] as $match) { + $this->elements[$match] = true; + } + + // setup all elements as parentheticals with leading commas + $reg = preg_replace("/$el/", '(,\\0)', $reg); + + // remove commas when they were not solicited + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); + + // remove all non-paranthetical commas: they are handled by first regex + $reg = preg_replace("/,\(/", '(', $reg); + + $this->_pcre_regex = $reg; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + $list_of_children = ''; + $nesting = 0; // depth into the nest + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + continue; + } + $list_of_children .= $node->name . ','; + } + // add leading comma to deal with stray comma declarations + $list_of_children = ',' . rtrim($list_of_children, ','); + $okay = + preg_match( + '/^,?' . $this->_pcre_regex . '$/', + $list_of_children + ); + return (bool)$okay; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php new file mode 100644 index 0000000000..a8a6cbdd2c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php @@ -0,0 +1,38 @@ + true, 'ul' => true, 'ol' => true); + + public $whitespace; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // if li is not allowed, delete parent node + if (!isset($config->getHTMLDefinition()->info['li'])) { + trigger_error("Cannot allow ul/ol without allowing li", E_USER_WARNING); + return false; + } + + // the new set of children + $result = array(); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $current_li = null; + + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if ($node->name === 'li') { + // good + $current_li = $node; + $result[] = $node; + } else { + // we want to tuck this into the previous li + // Invariant: we expect the node to be ol/ul + // ToDo: Make this more robust in the case of not ol/ul + // by distinguishing between existing li and li created + // to handle non-list elements; non-list elements should + // not be appended to an existing li; only li created + // for non-list. This distinction is not currently made. + if ($current_li === null) { + $current_li = new HTMLPurifier_Node_Element('li'); + $result[] = $current_li; + } + $current_li->children[] = $node; + $current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo + } + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php new file mode 100644 index 0000000000..b9468063b1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php @@ -0,0 +1,45 @@ +whitespace) { + return $children; + } else { + return array(); + } + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php new file mode 100644 index 0000000000..0d1c8f5f39 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php @@ -0,0 +1,118 @@ + $x) { + $elements[$i] = true; + if (empty($i)) { + unset($elements[$i]); + } // remove blank + } + } + $this->elements = $elements; + } + + /** + * @type bool + */ + public $allow_empty = false; + + /** + * @type string + */ + public $type = 'required'; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // the new set of children + $result = array(); + + // whether or not parsed character data is allowed + // this controls whether or not we silently drop a tag + // or generate escaped HTML from it + $pcdata_allowed = isset($this->elements['#PCDATA']); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $stack = array_reverse($children); + while (!empty($stack)) { + $node = array_pop($stack); + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if (!isset($this->elements[$node->name])) { + // special case text + // XXX One of these ought to be redundant or something + if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) { + $result[] = $node; + continue; + } + // spill the child contents in + // ToDo: Make configurable + if ($node instanceof HTMLPurifier_Node_Element) { + for ($i = count($node->children) - 1; $i >= 0; $i--) { + $stack[] = $node->children[$i]; + } + continue; + } + continue; + } + $result[] = $node; + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + $this->whitespace = true; + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php new file mode 100644 index 0000000000..3270a46e1b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php @@ -0,0 +1,110 @@ +init($config); + return $this->fake_elements; + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + $this->init($config); + + // trick the parent class into thinking it allows more + $this->elements = $this->fake_elements; + $result = parent::validateChildren($children, $config, $context); + $this->elements = $this->real_elements; + + if ($result === false) { + return array(); + } + if ($result === true) { + $result = $children; + } + + $def = $config->getHTMLDefinition(); + $block_wrap_name = $def->info_block_wrapper; + $block_wrap = false; + $ret = array(); + + foreach ($result as $node) { + if ($block_wrap === false) { + if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) || + ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) { + $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper); + $ret[] = $block_wrap; + } + } else { + if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) { + $block_wrap = false; + + } + } + if ($block_wrap) { + $block_wrap->children[] = $node; + } else { + $ret[] = $node; + } + } + return $ret; + } + + /** + * @param HTMLPurifier_Config $config + */ + private function init($config) + { + if (!$this->init) { + $def = $config->getHTMLDefinition(); + // allow all inline elements + $this->real_elements = $this->elements; + $this->fake_elements = $def->info_content_sets['Flow']; + $this->fake_elements['#PCDATA'] = true; + $this->init = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php new file mode 100644 index 0000000000..d92205b321 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php @@ -0,0 +1,227 @@ + true, + 'tbody' => true, + 'thead' => true, + 'tfoot' => true, + 'caption' => true, + 'colgroup' => true, + 'col' => true + ); + + public function __construct() + { + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + if (empty($children)) { + return false; + } + + // only one of these elements is allowed in a table + $caption = false; + $thead = false; + $tfoot = false; + + // whitespace + $initial_ws = array(); + $after_caption_ws = array(); + $after_thead_ws = array(); + $after_tfoot_ws = array(); + + // as many of these as you want + $cols = array(); + $content = array(); + + $tbody_mode = false; // if true, then we need to wrap any stray + //

s with a . + + $ws_accum =& $initial_ws; + + foreach ($children as $node) { + if ($node instanceof HTMLPurifier_Node_Comment) { + $ws_accum[] = $node; + continue; + } + switch ($node->name) { + case 'tbody': + $tbody_mode = true; + // fall through + case 'tr': + $content[] = $node; + $ws_accum =& $content; + break; + case 'caption': + // there can only be one caption! + if ($caption !== false) break; + $caption = $node; + $ws_accum =& $after_caption_ws; + break; + case 'thead': + $tbody_mode = true; + // XXX This breaks rendering properties with + // Firefox, which never floats a to + // the top. Ever. (Our scheme will float the + // first to the top.) So maybe + // s that are not first should be + // turned into ? Very tricky, indeed. + if ($thead === false) { + $thead = $node; + $ws_accum =& $after_thead_ws; + } else { + // Oops, there's a second one! What + // should we do? Current behavior is to + // transmutate the first and last entries into + // tbody tags, and then put into content. + // Maybe a better idea is to *attach + // it* to the existing thead or tfoot? + // We don't do this, because Firefox + // doesn't float an extra tfoot to the + // bottom like it does for the first one. + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'tfoot': + // see above for some aveats + $tbody_mode = true; + if ($tfoot === false) { + $tfoot = $node; + $ws_accum =& $after_tfoot_ws; + } else { + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'colgroup': + case 'col': + $cols[] = $node; + $ws_accum =& $cols; + break; + case '#PCDATA': + // How is whitespace handled? We treat is as sticky to + // the *end* of the previous element. So all of the + // nonsense we have worked on is to keep things + // together. + if (!empty($node->is_whitespace)) { + $ws_accum[] = $node; + } + break; + } + } + + if (empty($content) && $thead === false && $tfoot === false) { + return false; + } + + $ret = $initial_ws; + if ($caption !== false) { + $ret[] = $caption; + $ret = array_merge($ret, $after_caption_ws); + } + if ($cols !== false) { + $ret = array_merge($ret, $cols); + } + if ($thead !== false) { + $ret[] = $thead; + $ret = array_merge($ret, $after_thead_ws); + } + if ($tfoot !== false) { + $ret[] = $tfoot; + $ret = array_merge($ret, $after_tfoot_ws); + } + + if ($tbody_mode) { + // we have to shuffle tr into tbody + $current_tr_tbody = null; + + foreach($content as $node) { + if (!isset($node->name)) { + continue; + } + switch ($node->name) { + case 'tbody': + $current_tr_tbody = null; + $ret[] = $node; + break; + case 'tr': + if ($current_tr_tbody === null) { + $current_tr_tbody = new HTMLPurifier_Node_Element('tbody'); + $ret[] = $current_tr_tbody; + } + $current_tr_tbody->children[] = $node; + break; + case '#PCDATA': + //assert($node->is_whitespace); + if ($current_tr_tbody === null) { + $ret[] = $node; + } else { + $current_tr_tbody->children[] = $node; + } + break; + } + } + } else { + $ret = array_merge($ret, $content); + } + + return $ret; + + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php new file mode 100644 index 0000000000..e6566e802b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php @@ -0,0 +1,920 @@ +defaultPlist; + $this->plist = new HTMLPurifier_PropertyList($parent); + $this->def = $definition; // keep a copy around for checking + $this->parser = new HTMLPurifier_VarParser_Flexible(); + } + + /** + * Convenience constructor that creates a config object based on a mixed var + * @param mixed $config Variable that defines the state of the config + * object. Can be: a HTMLPurifier_Config() object, + * an array of directives based on loadArray(), + * or a string filename of an ini file. + * @param HTMLPurifier_ConfigSchema $schema Schema object + * @return HTMLPurifier_Config Configured object + */ + public static function create($config, $schema = null) + { + if ($config instanceof HTMLPurifier_Config) { + // pass-through + return $config; + } + if (!$schema) { + $ret = HTMLPurifier_Config::createDefault(); + } else { + $ret = new HTMLPurifier_Config($schema); + } + if (is_string($config)) { + $ret->loadIni($config); + } elseif (is_array($config)) $ret->loadArray($config); + return $ret; + } + + /** + * Creates a new config object that inherits from a previous one. + * @param HTMLPurifier_Config $config Configuration object to inherit from. + * @return HTMLPurifier_Config object with $config as its parent. + */ + public static function inherit(HTMLPurifier_Config $config) + { + return new HTMLPurifier_Config($config->def, $config->plist); + } + + /** + * Convenience constructor that creates a default configuration object. + * @return HTMLPurifier_Config default object. + */ + public static function createDefault() + { + $definition = HTMLPurifier_ConfigSchema::instance(); + $config = new HTMLPurifier_Config($definition); + return $config; + } + + /** + * Retrieves a value from the configuration. + * + * @param string $key String key + * @param mixed $a + * + * @return mixed + */ + public function get($key, $a = null) + { + if ($a !== null) { + $this->triggerError( + "Using deprecated API: use \$config->get('$key.$a') instead", + E_USER_WARNING + ); + $key = "$key.$a"; + } + if (!$this->finalized) { + $this->autoFinalize(); + } + if (!isset($this->def->info[$key])) { + // can't add % due to SimpleTest bug + $this->triggerError( + 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key), + E_USER_WARNING + ); + return; + } + if (isset($this->def->info[$key]->isAlias)) { + $d = $this->def->info[$key]; + $this->triggerError( + 'Cannot get value from aliased directive, use real name ' . $d->key, + E_USER_ERROR + ); + return; + } + if ($this->lock) { + list($ns) = explode('.', $key); + if ($ns !== $this->lock) { + $this->triggerError( + 'Cannot get value of namespace ' . $ns . ' when lock for ' . + $this->lock . + ' is active, this probably indicates a Definition setup method ' . + 'is accessing directives that are not within its namespace', + E_USER_ERROR + ); + return; + } + } + return $this->plist->get($key); + } + + /** + * Retrieves an array of directives to values from a given namespace + * + * @param string $namespace String namespace + * + * @return array + */ + public function getBatch($namespace) + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $full = $this->getAll(); + if (!isset($full[$namespace])) { + $this->triggerError( + 'Cannot retrieve undefined namespace ' . + htmlspecialchars($namespace), + E_USER_WARNING + ); + return; + } + return $full[$namespace]; + } + + /** + * Returns a SHA-1 signature of a segment of the configuration object + * that uniquely identifies that particular configuration + * + * @param string $namespace Namespace to get serial for + * + * @return string + * @note Revision is handled specially and is removed from the batch + * before processing! + */ + public function getBatchSerial($namespace) + { + if (empty($this->serials[$namespace])) { + $batch = $this->getBatch($namespace); + unset($batch['DefinitionRev']); + $this->serials[$namespace] = sha1(serialize($batch)); + } + return $this->serials[$namespace]; + } + + /** + * Returns a SHA-1 signature for the entire configuration object + * that uniquely identifies that particular configuration + * + * @return string + */ + public function getSerial() + { + if (empty($this->serial)) { + $this->serial = sha1(serialize($this->getAll())); + } + return $this->serial; + } + + /** + * Retrieves all directives, organized by namespace + * + * @warning This is a pretty inefficient function, avoid if you can + */ + public function getAll() + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $ret = array(); + foreach ($this->plist->squash() as $name => $value) { + list($ns, $key) = explode('.', $name, 2); + $ret[$ns][$key] = $value; + } + return $ret; + } + + /** + * Sets a value to configuration. + * + * @param string $key key + * @param mixed $value value + * @param mixed $a + */ + public function set($key, $value, $a = null) + { + if (strpos($key, '.') === false) { + $namespace = $key; + $directive = $value; + $value = $a; + $key = "$key.$directive"; + $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); + } else { + list($namespace) = explode('.', $key); + } + if ($this->isFinalized('Cannot set directive after finalization')) { + return; + } + if (!isset($this->def->info[$key])) { + $this->triggerError( + 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', + E_USER_WARNING + ); + return; + } + $def = $this->def->info[$key]; + + if (isset($def->isAlias)) { + if ($this->aliasMode) { + $this->triggerError( + 'Double-aliases not allowed, please fix '. + 'ConfigSchema bug with' . $key, + E_USER_ERROR + ); + return; + } + $this->aliasMode = true; + $this->set($def->key, $value); + $this->aliasMode = false; + $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); + return; + } + + // Raw type might be negative when using the fully optimized form + // of stdClass, which indicates allow_null == true + $rtype = is_int($def) ? $def : $def->type; + if ($rtype < 0) { + $type = -$rtype; + $allow_null = true; + } else { + $type = $rtype; + $allow_null = isset($def->allow_null); + } + + try { + $value = $this->parser->parse($value, $type, $allow_null); + } catch (HTMLPurifier_VarParserException $e) { + $this->triggerError( + 'Value for ' . $key . ' is of invalid type, should be ' . + HTMLPurifier_VarParser::getTypeName($type), + E_USER_WARNING + ); + return; + } + if (is_string($value) && is_object($def)) { + // resolve value alias if defined + if (isset($def->aliases[$value])) { + $value = $def->aliases[$value]; + } + // check to see if the value is allowed + if (isset($def->allowed) && !isset($def->allowed[$value])) { + $this->triggerError( + 'Value not supported, valid values are: ' . + $this->_listify($def->allowed), + E_USER_WARNING + ); + return; + } + } + $this->plist->set($key, $value); + + // reset definitions if the directives they depend on changed + // this is a very costly process, so it's discouraged + // with finalization + if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { + $this->definitions[$namespace] = null; + } + + $this->serials[$namespace] = false; + } + + /** + * Convenience function for error reporting + * + * @param array $lookup + * + * @return string + */ + private function _listify($lookup) + { + $list = array(); + foreach ($lookup as $name => $b) { + $list[] = $name; + } + return implode(', ', $list); + } + + /** + * Retrieves object reference to the HTML definition. + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawHTMLDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_HTMLDefinition|null + */ + public function getHTMLDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('HTML', $raw, $optimized); + } + + /** + * Retrieves object reference to the CSS definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawCSSDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_CSSDefinition|null + */ + public function getCSSDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('CSS', $raw, $optimized); + } + + /** + * Retrieves object reference to the URI definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawURIDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_URIDefinition|null + */ + public function getURIDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('URI', $raw, $optimized); + } + + /** + * Retrieves a definition + * + * @param string $type Type of definition: HTML, CSS, etc + * @param bool $raw Whether or not definition should be returned raw + * @param bool $optimized Only has an effect when $raw is true. Whether + * or not to return null if the result is already present in + * the cache. This is off by default for backwards + * compatibility reasons, but you need to do things this + * way in order to ensure that caching is done properly. + * Check out enduser-customize.html for more details. + * We probably won't ever change this default, as much as the + * maybe semantics is the "right thing to do." + * + * @throws HTMLPurifier_Exception + * @return HTMLPurifier_Definition|null + */ + public function getDefinition($type, $raw = false, $optimized = false) + { + if ($optimized && !$raw) { + throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); + } + if (!$this->finalized) { + $this->autoFinalize(); + } + // temporarily suspend locks, so we can handle recursive definition calls + $lock = $this->lock; + $this->lock = null; + $factory = HTMLPurifier_DefinitionCacheFactory::instance(); + $cache = $factory->create($type, $this); + $this->lock = $lock; + if (!$raw) { + // full definition + // --------------- + // check if definition is in memory + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + // check if the definition is setup + if ($def->setup) { + return $def; + } else { + $def->setup($this); + if ($def->optimized) { + $cache->add($def, $this); + } + return $def; + } + } + // check if definition is in cache + $def = $cache->get($this); + if ($def) { + // definition in cache, save to memory and return it + $this->definitions[$type] = $def; + return $def; + } + // initialize it + $def = $this->initDefinition($type); + // set it up + $this->lock = $type; + $def->setup($this); + $this->lock = null; + // save in cache + $cache->add($def, $this); + // return it + return $def; + } else { + // raw definition + // -------------- + // check preconditions + $def = null; + if ($optimized) { + if (is_null($this->get($type . '.DefinitionID'))) { + // fatally error out if definition ID not set + throw new HTMLPurifier_Exception( + "Cannot retrieve raw version without specifying %$type.DefinitionID" + ); + } + } + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + if ($def->setup && !$optimized) { + $extra = $this->chatty ? + " (try moving this code block earlier in your initialization)" : + ""; + throw new HTMLPurifier_Exception( + "Cannot retrieve raw definition after it has already been setup" . + $extra + ); + } + if ($def->optimized === null) { + $extra = $this->chatty ? " (try flushing your cache)" : ""; + throw new HTMLPurifier_Exception( + "Optimization status of definition is unknown" . $extra + ); + } + if ($def->optimized !== $optimized) { + $msg = $optimized ? "optimized" : "unoptimized"; + $extra = $this->chatty ? + " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" + : ""; + throw new HTMLPurifier_Exception( + "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra + ); + } + } + // check if definition was in memory + if ($def) { + if ($def->setup) { + // invariant: $optimized === true (checked above) + return null; + } else { + return $def; + } + } + // if optimized, check if definition was in cache + // (because we do the memory check first, this formulation + // is prone to cache slamming, but I think + // guaranteeing that either /all/ of the raw + // setup code or /none/ of it is run is more important.) + if ($optimized) { + // This code path only gets run once; once we put + // something in $definitions (which is guaranteed by the + // trailing code), we always short-circuit above. + $def = $cache->get($this); + if ($def) { + // save the full definition for later, but don't + // return it yet + $this->definitions[$type] = $def; + return null; + } + } + // check invariants for creation + if (!$optimized) { + if (!is_null($this->get($type . '.DefinitionID'))) { + if ($this->chatty) { + $this->triggerError( + 'Due to a documentation error in previous version of HTML Purifier, your ' . + 'definitions are not being cached. If this is OK, you can remove the ' . + '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' . + 'modify your code to use maybeGetRawDefinition, and test if the returned ' . + 'value is null before making any edits (if it is null, that means that a ' . + 'cached version is available, and no raw operations are necessary). See ' . + '' . + 'Customize for more details', + E_USER_WARNING + ); + } else { + $this->triggerError( + "Useless DefinitionID declaration", + E_USER_WARNING + ); + } + } + } + // initialize it + $def = $this->initDefinition($type); + $def->optimized = $optimized; + return $def; + } + throw new HTMLPurifier_Exception("The impossible happened!"); + } + + /** + * Initialise definition + * + * @param string $type What type of definition to create + * + * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition + * @throws HTMLPurifier_Exception + */ + private function initDefinition($type) + { + // quick checks failed, let's create the object + if ($type == 'HTML') { + $def = new HTMLPurifier_HTMLDefinition(); + } elseif ($type == 'CSS') { + $def = new HTMLPurifier_CSSDefinition(); + } elseif ($type == 'URI') { + $def = new HTMLPurifier_URIDefinition(); + } else { + throw new HTMLPurifier_Exception( + "Definition of $type type not supported" + ); + } + $this->definitions[$type] = $def; + return $def; + } + + public function maybeGetRawDefinition($name) + { + return $this->getDefinition($name, true, true); + } + + /** + * @return HTMLPurifier_HTMLDefinition|null + */ + public function maybeGetRawHTMLDefinition() + { + return $this->getDefinition('HTML', true, true); + } + + /** + * @return HTMLPurifier_CSSDefinition|null + */ + public function maybeGetRawCSSDefinition() + { + return $this->getDefinition('CSS', true, true); + } + + /** + * @return HTMLPurifier_URIDefinition|null + */ + public function maybeGetRawURIDefinition() + { + return $this->getDefinition('URI', true, true); + } + + /** + * Loads configuration values from an array with the following structure: + * Namespace.Directive => Value + * + * @param array $config_array Configuration associative array + */ + public function loadArray($config_array) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + foreach ($config_array as $key => $value) { + $key = str_replace('_', '.', $key); + if (strpos($key, '.') !== false) { + $this->set($key, $value); + } else { + $namespace = $key; + $namespace_values = $value; + foreach ($namespace_values as $directive => $value2) { + $this->set($namespace .'.'. $directive, $value2); + } + } + } + } + + /** + * Returns a list of array(namespace, directive) for all directives + * that are allowed in a web-form context as per an allowed + * namespaces/directives list. + * + * @param array $allowed List of allowed namespaces/directives + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function getAllowedDirectivesForForm($allowed, $schema = null) + { + if (!$schema) { + $schema = HTMLPurifier_ConfigSchema::instance(); + } + if ($allowed !== true) { + if (is_string($allowed)) { + $allowed = array($allowed); + } + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } + } + $ret = array(); + foreach ($schema->info as $key => $def) { + list($ns, $directive) = explode('.', $key, 2); + if ($allowed !== true) { + if (isset($blacklisted_directives["$ns.$directive"])) { + continue; + } + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) { + continue; + } + } + if (isset($def->isAlias)) { + continue; + } + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') { + continue; + } + $ret[] = array($ns, $directive); + } + return $ret; + } + + /** + * Loads configuration values from $_GET/$_POST that were posted + * via ConfigForm + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return mixed + */ + public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); + $config = HTMLPurifier_Config::create($ret, $schema); + return $config; + } + + /** + * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + */ + public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); + $this->loadArray($ret); + } + + /** + * Prepares an array from a form into something usable for the more + * strict parts of HTMLPurifier_Config + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + if ($index !== false) { + $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + } + $mq = $mq_fix && version_compare(PHP_VERSION, '7.4.0', '<') && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); + $ret = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $skey = "$ns.$directive"; + if (!empty($array["Null_$skey"])) { + $ret[$ns][$directive] = null; + continue; + } + if (!isset($array[$skey])) { + continue; + } + $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; + $ret[$ns][$directive] = $value; + } + return $ret; + } + + /** + * Loads configuration values from an ini file + * + * @param string $filename Name of ini file + */ + public function loadIni($filename) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + $array = parse_ini_file($filename, true); + $this->loadArray($array); + } + + /** + * Checks whether or not the configuration object is finalized. + * + * @param string|bool $error String error message, or false for no error + * + * @return bool + */ + public function isFinalized($error = false) + { + if ($this->finalized && $error) { + $this->triggerError($error, E_USER_ERROR); + } + return $this->finalized; + } + + /** + * Finalizes configuration only if auto finalize is on and not + * already finalized + */ + public function autoFinalize() + { + if ($this->autoFinalize) { + $this->finalize(); + } else { + $this->plist->squash(true); + } + } + + /** + * Finalizes a configuration object, prohibiting further change + */ + public function finalize() + { + $this->finalized = true; + $this->parser = null; + } + + /** + * Produces a nicely formatted error message by supplying the + * stack frame information OUTSIDE of HTMLPurifier_Config. + * + * @param string $msg An error message + * @param int $no An error number + */ + protected function triggerError($msg, $no) + { + // determine previous stack frame + $extra = ''; + if ($this->chatty) { + $trace = debug_backtrace(); + // zip(tail(trace), trace) -- but PHP is not Haskell har har + for ($i = 0, $c = count($trace); $i < $c - 1; $i++) { + // XXX this is not correct on some versions of HTML Purifier + if (isset($trace[$i + 1]['class']) && $trace[$i + 1]['class'] === 'HTMLPurifier_Config') { + continue; + } + $frame = $trace[$i]; + $extra = " invoked on line {$frame['line']} in file {$frame['file']}"; + break; + } + } + trigger_error($msg . $extra, $no); + } + + /** + * Returns a serialized form of the configuration object that can + * be reconstituted. + * + * @return string + */ + public function serialize() + { + $this->getDefinition('HTML'); + $this->getDefinition('CSS'); + $this->getDefinition('URI'); + return serialize($this); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php new file mode 100644 index 0000000000..c3fe8cd4ab --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php @@ -0,0 +1,176 @@ + array( + * 'Directive' => new stdClass(), + * ) + * ) + * + * The stdClass may have the following properties: + * + * - If isAlias isn't set: + * - type: Integer type of directive, see HTMLPurifier_VarParser for definitions + * - allow_null: If set, this directive allows null values + * - aliases: If set, an associative array of value aliases to real values + * - allowed: If set, a lookup array of allowed (string) values + * - If isAlias is set: + * - namespace: Namespace this directive aliases to + * - name: Directive name this directive aliases to + * + * In certain degenerate cases, stdClass will actually be an integer. In + * that case, the value is equivalent to an stdClass with the type + * property set to the integer. If the integer is negative, type is + * equal to the absolute value of integer, and allow_null is true. + * + * This class is friendly with HTMLPurifier_Config. If you need introspection + * about the schema, you're better of using the ConfigSchema_Interchange, + * which uses more memory but has much richer information. + * @type array + */ + public $info = array(); + + /** + * Application-wide singleton + * @type HTMLPurifier_ConfigSchema + */ + protected static $singleton; + + public function __construct() + { + $this->defaultPlist = new HTMLPurifier_PropertyList(); + } + + /** + * Unserializes the default ConfigSchema. + * @return HTMLPurifier_ConfigSchema + */ + public static function makeFromSerial() + { + $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'); + $r = unserialize($contents); + if (!$r) { + $hash = sha1($contents); + trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR); + } + return $r; + } + + /** + * Retrieves an instance of the application-wide configuration definition. + * @param HTMLPurifier_ConfigSchema $prototype + * @return HTMLPurifier_ConfigSchema + */ + public static function instance($prototype = null) + { + if ($prototype !== null) { + HTMLPurifier_ConfigSchema::$singleton = $prototype; + } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) { + HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial(); + } + return HTMLPurifier_ConfigSchema::$singleton; + } + + /** + * Defines a directive for configuration + * @warning Will fail of directive's namespace is defined. + * @warning This method's signature is slightly different from the legacy + * define() static method! Beware! + * @param string $key Name of directive + * @param mixed $default Default value of directive + * @param string $type Allowed type of the directive. See + * HTMLPurifier_VarParser::$types for allowed values + * @param bool $allow_null Whether or not to allow null values + */ + public function add($key, $default, $type, $allow_null) + { + $obj = new stdClass(); + $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type]; + if ($allow_null) { + $obj->allow_null = true; + } + $this->info[$key] = $obj; + $this->defaults[$key] = $default; + $this->defaultPlist->set($key, $default); + } + + /** + * Defines a directive value alias. + * + * Directive value aliases are convenient for developers because it lets + * them set a directive to several values and get the same result. + * @param string $key Name of Directive + * @param array $aliases Hash of aliased values to the real alias + */ + public function addValueAliases($key, $aliases) + { + if (!isset($this->info[$key]->aliases)) { + $this->info[$key]->aliases = array(); + } + foreach ($aliases as $alias => $real) { + $this->info[$key]->aliases[$alias] = $real; + } + } + + /** + * Defines a set of allowed values for a directive. + * @warning This is slightly different from the corresponding static + * method definition. + * @param string $key Name of directive + * @param array $allowed Lookup array of allowed values + */ + public function addAllowedValues($key, $allowed) + { + $this->info[$key]->allowed = $allowed; + } + + /** + * Defines a directive alias for backwards compatibility + * @param string $key Directive that will be aliased + * @param string $new_key Directive that the alias will be to + */ + public function addAlias($key, $new_key) + { + $obj = new stdClass; + $obj->key = $new_key; + $obj->isAlias = true; + $this->info[$key] = $obj; + } + + /** + * Replaces any stdClass that only has the type property with type integer. + */ + public function postProcess() + { + foreach ($this->info as $key => $v) { + if (count((array) $v) == 1) { + $this->info[$key] = $v->type; + } elseif (count((array) $v) == 2 && isset($v->allow_null)) { + $this->info[$key] = -$v->type; + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php new file mode 100644 index 0000000000..d5906cd46d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php @@ -0,0 +1,48 @@ +directives as $d) { + $schema->add( + $d->id->key, + $d->default, + $d->type, + $d->typeAllowsNull + ); + if ($d->allowed !== null) { + $schema->addAllowedValues( + $d->id->key, + $d->allowed + ); + } + foreach ($d->aliases as $alias) { + $schema->addAlias( + $alias->key, + $d->id->key + ); + } + if ($d->valueAliases !== null) { + $schema->addValueAliases( + $d->id->key, + $d->valueAliases + ); + } + } + $schema->postProcess(); + return $schema; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php new file mode 100644 index 0000000000..5fa56f7ddb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php @@ -0,0 +1,144 @@ +startElement('div'); + + $purifier = HTMLPurifier::getInstance(); + $html = $purifier->purify($html); + $this->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $this->writeRaw($html); + + $this->endElement(); // div + } + + /** + * @param mixed $var + * @return string + */ + protected function export($var) + { + if ($var === array()) { + return 'array()'; + } + return var_export($var, true); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + */ + public function build($interchange) + { + // global access, only use as last resort + $this->interchange = $interchange; + + $this->setIndent(true); + $this->startDocument('1.0', 'UTF-8'); + $this->startElement('configdoc'); + $this->writeElement('title', $interchange->name); + + foreach ($interchange->directives as $directive) { + $this->buildDirective($directive); + } + + if ($this->namespace) { + $this->endElement(); + } // namespace + + $this->endElement(); // configdoc + $this->flush(); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + */ + public function buildDirective($directive) + { + // Kludge, although I suppose having a notion of a "root namespace" + // certainly makes things look nicer when documentation is built. + // Depends on things being sorted. + if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) { + if ($this->namespace) { + $this->endElement(); + } // namespace + $this->namespace = $directive->id->getRootNamespace(); + $this->startElement('namespace'); + $this->writeAttribute('id', $this->namespace); + $this->writeElement('name', $this->namespace); + } + + $this->startElement('directive'); + $this->writeAttribute('id', $directive->id->toString()); + + $this->writeElement('name', $directive->id->getDirective()); + + $this->startElement('aliases'); + foreach ($directive->aliases as $alias) { + $this->writeElement('alias', $alias->toString()); + } + $this->endElement(); // aliases + + $this->startElement('constraints'); + if ($directive->version) { + $this->writeElement('version', $directive->version); + } + $this->startElement('type'); + if ($directive->typeAllowsNull) { + $this->writeAttribute('allow-null', 'yes'); + } + $this->text($directive->type); + $this->endElement(); // type + if ($directive->allowed) { + $this->startElement('allowed'); + foreach ($directive->allowed as $value => $x) { + $this->writeElement('value', $value); + } + $this->endElement(); // allowed + } + $this->writeElement('default', $this->export($directive->default)); + $this->writeAttribute('xml:space', 'preserve'); + if ($directive->external) { + $this->startElement('external'); + foreach ($directive->external as $project) { + $this->writeElement('project', $project); + } + $this->endElement(); + } + $this->endElement(); // constraints + + if ($directive->deprecatedVersion) { + $this->startElement('deprecated'); + $this->writeElement('version', $directive->deprecatedVersion); + $this->writeElement('use', $directive->deprecatedUse->toString()); + $this->endElement(); // deprecated + } + + $this->startElement('description'); + $this->writeHTMLDiv($directive->description); + $this->endElement(); // description + + $this->endElement(); // directive + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php new file mode 100644 index 0000000000..2671516c58 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php @@ -0,0 +1,11 @@ + array(directive info) + * @type HTMLPurifier_ConfigSchema_Interchange_Directive[] + */ + public $directives = array(); + + /** + * Adds a directive array to $directives + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function addDirective($directive) + { + if (isset($this->directives[$i = $directive->id->toString()])) { + throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'"); + } + $this->directives[$i] = $directive; + } + + /** + * Convenience function to perform standard validation. Throws exception + * on failed validation. + */ + public function validate() + { + $validator = new HTMLPurifier_ConfigSchema_Validator(); + return $validator->validate($this); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php new file mode 100644 index 0000000000..127a39a673 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php @@ -0,0 +1,89 @@ + true). + * Null if all values are allowed. + * @type array + */ + public $allowed; + + /** + * List of aliases for the directive. + * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))). + * @type HTMLPurifier_ConfigSchema_Interchange_Id[] + */ + public $aliases = array(); + + /** + * Hash of value aliases, e.g. array('alt' => 'real'). Null if value + * aliasing is disabled (necessary for non-scalar types). + * @type array + */ + public $valueAliases; + + /** + * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'. + * Null if the directive has always existed. + * @type string + */ + public $version; + + /** + * ID of directive that supercedes this old directive. + * Null if not deprecated. + * @type HTMLPurifier_ConfigSchema_Interchange_Id + */ + public $deprecatedUse; + + /** + * Version of HTML Purifier this directive was deprecated. Null if not + * deprecated. + * @type string + */ + public $deprecatedVersion; + + /** + * List of external projects this directive depends on, e.g. array('CSSTidy'). + * @type array + */ + public $external = array(); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php new file mode 100644 index 0000000000..126f09d957 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php @@ -0,0 +1,58 @@ +key = $key; + } + + /** + * @return string + * @warning This is NOT magic, to ensure that people don't abuse SPL and + * cause problems for PHP 5.0 support. + */ + public function toString() + { + return $this->key; + } + + /** + * @return string + */ + public function getRootNamespace() + { + return substr($this->key, 0, strpos($this->key, ".")); + } + + /** + * @return string + */ + public function getDirective() + { + return substr($this->key, strpos($this->key, ".") + 1); + } + + /** + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + public static function make($id) + { + return new HTMLPurifier_ConfigSchema_Interchange_Id($id); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php new file mode 100644 index 0000000000..655e6dd1b9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php @@ -0,0 +1,226 @@ +varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); + } + + /** + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public static function buildFromDirectory($dir = null) + { + $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); + $interchange = new HTMLPurifier_ConfigSchema_Interchange(); + return $builder->buildDir($interchange, $dir); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public function buildDir($interchange, $dir = null) + { + if (!$dir) { + $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; + } + if (file_exists($dir . '/info.ini')) { + $info = parse_ini_file($dir . '/info.ini'); + $interchange->name = $info['name']; + } + + $files = array(); + $dh = opendir($dir); + while (false !== ($file = readdir($dh))) { + if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { + continue; + } + $files[] = $file; + } + closedir($dh); + + sort($files); + foreach ($files as $file) { + $this->buildFile($interchange, $dir . '/' . $file); + } + return $interchange; + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $file + */ + public function buildFile($interchange, $file) + { + $parser = new HTMLPurifier_StringHashParser(); + $this->build( + $interchange, + new HTMLPurifier_StringHash($parser->parseFile($file)) + ); + } + + /** + * Builds an interchange object based on a hash. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build + * @param HTMLPurifier_StringHash $hash source data + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function build($interchange, $hash) + { + if (!$hash instanceof HTMLPurifier_StringHash) { + $hash = new HTMLPurifier_StringHash($hash); + } + if (!isset($hash['ID'])) { + throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); + } + if (strpos($hash['ID'], '.') === false) { + if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { + $hash->offsetGet('DESCRIPTION'); // prevent complaining + } else { + throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); + } + } else { + $this->buildDirective($interchange, $hash); + } + $this->_findUnused($hash); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param HTMLPurifier_StringHash $hash + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function buildDirective($interchange, $hash) + { + $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); + + // These are required elements: + $directive->id = $this->id($hash->offsetGet('ID')); + $id = $directive->id->toString(); // convenience + + if (isset($hash['TYPE'])) { + $type = explode('/', $hash->offsetGet('TYPE')); + if (isset($type[1])) { + $directive->typeAllowsNull = true; + } + $directive->type = $type[0]; + } else { + throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); + } + + if (isset($hash['DEFAULT'])) { + try { + $directive->default = $this->varParser->parse( + $hash->offsetGet('DEFAULT'), + $directive->type, + $directive->typeAllowsNull + ); + } catch (HTMLPurifier_VarParserException $e) { + throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); + } + } + + if (isset($hash['DESCRIPTION'])) { + $directive->description = $hash->offsetGet('DESCRIPTION'); + } + + if (isset($hash['ALLOWED'])) { + $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); + } + + if (isset($hash['VALUE-ALIASES'])) { + $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); + } + + if (isset($hash['ALIASES'])) { + $raw_aliases = trim($hash->offsetGet('ALIASES')); + $aliases = preg_split('/\s*,\s*/', $raw_aliases); + foreach ($aliases as $alias) { + $directive->aliases[] = $this->id($alias); + } + } + + if (isset($hash['VERSION'])) { + $directive->version = $hash->offsetGet('VERSION'); + } + + if (isset($hash['DEPRECATED-USE'])) { + $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); + } + + if (isset($hash['DEPRECATED-VERSION'])) { + $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); + } + + if (isset($hash['EXTERNAL'])) { + $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); + } + + $interchange->addDirective($directive); + } + + /** + * Evaluates an array PHP code string without array() wrapper + * @param string $contents + */ + protected function evalArray($contents) + { + return eval('return array(' . $contents . ');'); + } + + /** + * Converts an array list into a lookup array. + * @param array $array + * @return array + */ + protected function lookup($array) + { + $ret = array(); + foreach ($array as $val) { + $ret[$val] = true; + } + return $ret; + } + + /** + * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id + * object based on a string Id. + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + protected function id($id) + { + return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); + } + + /** + * Triggers errors for any unused keys passed in the hash; such keys + * may indicate typos, missing values, etc. + * @param HTMLPurifier_StringHash $hash Hash to check. + */ + protected function _findUnused($hash) + { + $accessed = $hash->getAccessed(); + foreach ($hash as $k => $v) { + if (!isset($accessed[$k])) { + trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php new file mode 100644 index 0000000000..fb31277889 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php @@ -0,0 +1,248 @@ +parser = new HTMLPurifier_VarParser(); + } + + /** + * Validates a fully-formed interchange object. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @return bool + */ + public function validate($interchange) + { + $this->interchange = $interchange; + $this->aliases = array(); + // PHP is a bit lax with integer <=> string conversions in + // arrays, so we don't use the identical !== comparison + foreach ($interchange->directives as $i => $directive) { + $id = $directive->id->toString(); + if ($i != $id) { + $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'"); + } + $this->validateDirective($directive); + } + return true; + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. + * @param HTMLPurifier_ConfigSchema_Interchange_Id $id + */ + public function validateId($id) + { + $id_string = $id->toString(); + $this->context[] = "id '$id_string'"; + if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { + // handled by InterchangeBuilder + $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id'); + } + // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.) + // we probably should check that it has at least one namespace + $this->with($id, 'key') + ->assertNotEmpty() + ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder + array_pop($this->context); + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirective($d) + { + $id = $d->id->toString(); + $this->context[] = "directive '$id'"; + $this->validateId($d->id); + + $this->with($d, 'description') + ->assertNotEmpty(); + + // BEGIN - handled by InterchangeBuilder + $this->with($d, 'type') + ->assertNotEmpty(); + $this->with($d, 'typeAllowsNull') + ->assertIsBool(); + try { + // This also tests validity of $d->type + $this->parser->parse($d->default, $d->type, $d->typeAllowsNull); + } catch (HTMLPurifier_VarParserException $e) { + $this->error('default', 'had error: ' . $e->getMessage()); + } + // END - handled by InterchangeBuilder + + if (!is_null($d->allowed) || !empty($d->valueAliases)) { + // allowed and valueAliases require that we be dealing with + // strings, so check for that early. + $d_int = HTMLPurifier_VarParser::$types[$d->type]; + if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) { + $this->error('type', 'must be a string type when used with allowed or value aliases'); + } + } + + $this->validateDirectiveAllowed($d); + $this->validateDirectiveValueAliases($d); + $this->validateDirectiveAliases($d); + + array_pop($this->context); + } + + /** + * Extra validation if $allowed member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAllowed($d) + { + if (is_null($d->allowed)) { + return; + } + $this->with($d, 'allowed') + ->assertNotEmpty() + ->assertIsLookup(); // handled by InterchangeBuilder + if (is_string($d->default) && !isset($d->allowed[$d->default])) { + $this->error('default', 'must be an allowed value'); + } + $this->context[] = 'allowed'; + foreach ($d->allowed as $val => $x) { + if (!is_string($val)) { + $this->error("value $val", 'must be a string'); + } + } + array_pop($this->context); + } + + /** + * Extra validation if $valueAliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveValueAliases($d) + { + if (is_null($d->valueAliases)) { + return; + } + $this->with($d, 'valueAliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'valueAliases'; + foreach ($d->valueAliases as $alias => $real) { + if (!is_string($alias)) { + $this->error("alias $alias", 'must be a string'); + } + if (!is_string($real)) { + $this->error("alias target $real from alias '$alias'", 'must be a string'); + } + if ($alias === $real) { + $this->error("alias '$alias'", "must not be an alias to itself"); + } + } + if (!is_null($d->allowed)) { + foreach ($d->valueAliases as $alias => $real) { + if (isset($d->allowed[$alias])) { + $this->error("alias '$alias'", 'must not be an allowed value'); + } elseif (!isset($d->allowed[$real])) { + $this->error("alias '$alias'", 'must be an alias to an allowed value'); + } + } + } + array_pop($this->context); + } + + /** + * Extra validation if $aliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAliases($d) + { + $this->with($d, 'aliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'aliases'; + foreach ($d->aliases as $alias) { + $this->validateId($alias); + $s = $alias->toString(); + if (isset($this->interchange->directives[$s])) { + $this->error("alias '$s'", 'collides with another directive'); + } + if (isset($this->aliases[$s])) { + $other_directive = $this->aliases[$s]; + $this->error("alias '$s'", "collides with alias for directive '$other_directive'"); + } + $this->aliases[$s] = $d->id->toString(); + } + array_pop($this->context); + } + + // protected helper functions + + /** + * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom + * for validating simple member variables of objects. + * @param $obj + * @param $member + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + protected function with($obj, $member) + { + return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member); + } + + /** + * Emits an error, providing helpful context. + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($target, $msg) + { + if ($target !== false) { + $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext(); + } else { + $prefix = ucfirst($this->getFormattedContext()); + } + throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg)); + } + + /** + * Returns a formatted context string. + * @return string + */ + protected function getFormattedContext() + { + return implode(' in ', array_reverse($this->context)); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php new file mode 100644 index 0000000000..c9aa3644af --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php @@ -0,0 +1,130 @@ +context = $context; + $this->obj = $obj; + $this->member = $member; + $this->contents =& $obj->$member; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsString() + { + if (!is_string($this->contents)) { + $this->error('must be a string'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsBool() + { + if (!is_bool($this->contents)) { + $this->error('must be a boolean'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsArray() + { + if (!is_array($this->contents)) { + $this->error('must be an array'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotNull() + { + if ($this->contents === null) { + $this->error('must not be null'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertAlnum() + { + $this->assertIsString(); + if (!ctype_alnum($this->contents)) { + $this->error('must be alphanumeric'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotEmpty() + { + if (empty($this->contents)) { + $this->error('must not be empty'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsLookup() + { + $this->assertIsArray(); + foreach ($this->contents as $v) { + if ($v !== true) { + $this->error('must be a lookup array'); + } + } + return $this; + } + + /** + * @param string $msg + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($msg) + { + throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser new file mode 100644 index 0000000000..3cd756beef --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser @@ -0,0 +1 @@ +O:25:"HTMLPurifier_ConfigSchema":3:{s:8:"defaults";a:128:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:17:"Core.RemoveBlanks";b:0;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:12:"defaultPlist";O:25:"HTMLPurifier_PropertyList":3:{s:7:"*data";a:128:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:17:"Core.RemoveBlanks";b:0;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:9:"*parent";N;s:8:"*cache";N;}s:4:"info";a:141:{s:19:"Attr.AllowedClasses";i:-8;s:24:"Attr.AllowedFrameTargets";i:8;s:15:"Attr.AllowedRel";i:8;s:15:"Attr.AllowedRev";i:8;s:18:"Attr.ClassUseCDATA";i:-7;s:20:"Attr.DefaultImageAlt";i:-1;s:24:"Attr.DefaultInvalidImage";i:1;s:27:"Attr.DefaultInvalidImageAlt";i:1;s:19:"Attr.DefaultTextDir";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:2:{s:3:"ltr";b:1;s:3:"rtl";b:1;}}s:13:"Attr.EnableID";i:7;s:17:"HTML.EnableAttrID";O:8:"stdClass":2:{s:3:"key";s:13:"Attr.EnableID";s:7:"isAlias";b:1;}s:21:"Attr.ForbiddenClasses";i:8;s:13:"Attr.ID.HTML5";i:-7;s:16:"Attr.IDBlacklist";i:9;s:22:"Attr.IDBlacklistRegexp";i:-1;s:13:"Attr.IDPrefix";i:1;s:18:"Attr.IDPrefixLocal";i:1;s:24:"AutoFormat.AutoParagraph";i:7;s:17:"AutoFormat.Custom";i:9;s:25:"AutoFormat.DisplayLinkURI";i:7;s:18:"AutoFormat.Linkify";i:7;s:33:"AutoFormat.PurifierLinkify.DocURL";i:1;s:37:"AutoFormatParam.PurifierLinkifyDocURL";O:8:"stdClass":2:{s:3:"key";s:33:"AutoFormat.PurifierLinkify.DocURL";s:7:"isAlias";b:1;}s:26:"AutoFormat.PurifierLinkify";i:7;s:32:"AutoFormat.RemoveEmpty.Predicate";i:10;s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";i:8;s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";i:7;s:22:"AutoFormat.RemoveEmpty";i:7;s:39:"AutoFormat.RemoveSpansWithoutAttributes";i:7;s:19:"CSS.AllowDuplicates";i:7;s:18:"CSS.AllowImportant";i:7;s:15:"CSS.AllowTricky";i:7;s:16:"CSS.AllowedFonts";i:-8;s:21:"CSS.AllowedProperties";i:-8;s:17:"CSS.DefinitionRev";i:5;s:23:"CSS.ForbiddenProperties";i:8;s:16:"CSS.MaxImgLength";i:-1;s:15:"CSS.Proprietary";i:7;s:11:"CSS.Trusted";i:7;s:20:"Cache.DefinitionImpl";i:-1;s:20:"Core.DefinitionCache";O:8:"stdClass":2:{s:3:"key";s:20:"Cache.DefinitionImpl";s:7:"isAlias";b:1;}s:20:"Cache.SerializerPath";i:-1;s:27:"Cache.SerializerPermissions";i:-5;s:22:"Core.AggressivelyFixLt";i:7;s:29:"Core.AggressivelyRemoveScript";i:7;s:28:"Core.AllowHostnameUnderscore";i:7;s:23:"Core.AllowParseManyTags";i:7;s:18:"Core.CollectErrors";i:7;s:18:"Core.ColorKeywords";i:10;s:30:"Core.ConvertDocumentToFragment";i:7;s:24:"Core.AcceptFullDocuments";O:8:"stdClass":2:{s:3:"key";s:30:"Core.ConvertDocumentToFragment";s:7:"isAlias";b:1;}s:36:"Core.DirectLexLineNumberSyncInterval";i:5;s:20:"Core.DisableExcludes";i:7;s:15:"Core.EnableIDNA";i:7;s:13:"Core.Encoding";i:2;s:26:"Core.EscapeInvalidChildren";i:7;s:22:"Core.EscapeInvalidTags";i:7;s:29:"Core.EscapeNonASCIICharacters";i:7;s:19:"Core.HiddenElements";i:8;s:13:"Core.Language";i:1;s:24:"Core.LegacyEntityDecoder";i:7;s:14:"Core.LexerImpl";i:-11;s:24:"Core.MaintainLineNumbers";i:-7;s:22:"Core.NormalizeNewlines";i:7;s:17:"Core.RemoveBlanks";i:7;s:21:"Core.RemoveInvalidImg";i:7;s:33:"Core.RemoveProcessingInstructions";i:7;s:25:"Core.RemoveScriptContents";i:-7;s:13:"Filter.Custom";i:9;s:34:"Filter.ExtractStyleBlocks.Escaping";i:7;s:33:"Filter.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:38:"FilterParam.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:31:"Filter.ExtractStyleBlocks.Scope";i:-1;s:30:"Filter.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:35:"FilterParam.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:34:"Filter.ExtractStyleBlocks.TidyImpl";i:-11;s:38:"FilterParam.ExtractStyleBlocksTidyImpl";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.TidyImpl";s:7:"isAlias";b:1;}s:25:"Filter.ExtractStyleBlocks";i:7;s:14:"Filter.YouTube";i:7;s:12:"HTML.Allowed";i:-4;s:22:"HTML.AllowedAttributes";i:-8;s:20:"HTML.AllowedComments";i:8;s:26:"HTML.AllowedCommentsRegexp";i:-1;s:20:"HTML.AllowedElements";i:-8;s:19:"HTML.AllowedModules";i:-8;s:23:"HTML.Attr.Name.UseCDATA";i:7;s:17:"HTML.BlockWrapper";i:1;s:16:"HTML.CoreModules";i:8;s:18:"HTML.CustomDoctype";i:-1;s:17:"HTML.DefinitionID";i:-1;s:18:"HTML.DefinitionRev";i:5;s:12:"HTML.Doctype";O:8:"stdClass":3:{s:4:"type";i:1;s:10:"allow_null";b:1;s:7:"allowed";a:5:{s:22:"HTML 4.01 Transitional";b:1;s:16:"HTML 4.01 Strict";b:1;s:22:"XHTML 1.0 Transitional";b:1;s:16:"XHTML 1.0 Strict";b:1;s:9:"XHTML 1.1";b:1;}}s:25:"HTML.FlashAllowFullScreen";i:7;s:24:"HTML.ForbiddenAttributes";i:8;s:22:"HTML.ForbiddenElements";i:8;s:10:"HTML.Forms";i:7;s:17:"HTML.MaxImgLength";i:-5;s:13:"HTML.Nofollow";i:7;s:11:"HTML.Parent";i:1;s:16:"HTML.Proprietary";i:7;s:14:"HTML.SafeEmbed";i:7;s:15:"HTML.SafeIframe";i:7;s:15:"HTML.SafeObject";i:7;s:18:"HTML.SafeScripting";i:8;s:11:"HTML.Strict";i:7;s:16:"HTML.TargetBlank";i:7;s:19:"HTML.TargetNoopener";i:7;s:21:"HTML.TargetNoreferrer";i:7;s:12:"HTML.TidyAdd";i:8;s:14:"HTML.TidyLevel";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:4:{s:4:"none";b:1;s:5:"light";b:1;s:6:"medium";b:1;s:5:"heavy";b:1;}}s:15:"HTML.TidyRemove";i:8;s:12:"HTML.Trusted";i:7;s:10:"HTML.XHTML";i:7;s:10:"Core.XHTML";O:8:"stdClass":2:{s:3:"key";s:10:"HTML.XHTML";s:7:"isAlias";b:1;}s:28:"Output.CommentScriptContents";i:7;s:26:"Core.CommentScriptContents";O:8:"stdClass":2:{s:3:"key";s:28:"Output.CommentScriptContents";s:7:"isAlias";b:1;}s:19:"Output.FixInnerHTML";i:7;s:18:"Output.FlashCompat";i:7;s:14:"Output.Newline";i:-1;s:15:"Output.SortAttr";i:7;s:17:"Output.TidyFormat";i:7;s:15:"Core.TidyFormat";O:8:"stdClass":2:{s:3:"key";s:17:"Output.TidyFormat";s:7:"isAlias";b:1;}s:17:"Test.ForceNoIconv";i:7;s:18:"URI.AllowedSchemes";i:8;s:8:"URI.Base";i:-1;s:17:"URI.DefaultScheme";i:-1;s:16:"URI.DefinitionID";i:-1;s:17:"URI.DefinitionRev";i:5;s:11:"URI.Disable";i:7;s:15:"Attr.DisableURI";O:8:"stdClass":2:{s:3:"key";s:11:"URI.Disable";s:7:"isAlias";b:1;}s:19:"URI.DisableExternal";i:7;s:28:"URI.DisableExternalResources";i:7;s:20:"URI.DisableResources";i:7;s:8:"URI.Host";i:-1;s:17:"URI.HostBlacklist";i:9;s:16:"URI.MakeAbsolute";i:7;s:9:"URI.Munge";i:-1;s:18:"URI.MungeResources";i:7;s:18:"URI.MungeSecretKey";i:-1;s:26:"URI.OverrideAllowedSchemes";i:7;s:20:"URI.SafeIframeRegexp";i:-1;}} \ No newline at end of file diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt new file mode 100644 index 0000000000..0517fed0a1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt @@ -0,0 +1,8 @@ +Attr.AllowedClasses +TYPE: lookup/null +VERSION: 4.0.0 +DEFAULT: null +--DESCRIPTION-- +List of allowed class values in the class attribute. By default, this is null, +which means all classes are allowed. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt new file mode 100644 index 0000000000..249edd647b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt @@ -0,0 +1,12 @@ +Attr.AllowedFrameTargets +TYPE: lookup +DEFAULT: array() +--DESCRIPTION-- +Lookup table of all allowed link frame targets. Some commonly used link +targets include _blank, _self, _parent and _top. Values should be +lowercase, as validation will be done in a case-sensitive manner despite +W3C's recommendation. XHTML 1.0 Strict does not permit the target attribute +so this directive will have no effect in that doctype. XHTML 1.1 does not +enable the Target module by default, you will have to manually enable it +(see the module documentation for more details.) +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt new file mode 100644 index 0000000000..9a8fa6a2e2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt @@ -0,0 +1,9 @@ +Attr.AllowedRel +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed forward document relationships in the rel attribute. Common +values may be nofollow or print. By default, this is empty, meaning that no +document relationships are allowed. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt new file mode 100644 index 0000000000..b017883485 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt @@ -0,0 +1,9 @@ +Attr.AllowedRev +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed reverse document relationships in the rev attribute. This +attribute is a bit of an edge-case; if you don't know what it is for, stay +away. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt new file mode 100644 index 0000000000..e774b823b1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt @@ -0,0 +1,19 @@ +Attr.ClassUseCDATA +TYPE: bool/null +DEFAULT: null +VERSION: 4.0.0 +--DESCRIPTION-- +If null, class will auto-detect the doctype and, if matching XHTML 1.1 or +XHTML 2.0, will use the restrictive NMTOKENS specification of class. Otherwise, +it will use a relaxed CDATA definition. If true, the relaxed CDATA definition +is forced; if false, the NMTOKENS definition is forced. To get behavior +of HTML Purifier prior to 4.0.0, set this directive to false. + +Some rational behind the auto-detection: +in previous versions of HTML Purifier, it was assumed that the form of +class was NMTOKENS, as specified by the XHTML Modularization (representing +XHTML 1.1 and XHTML 2.0). The DTDs for HTML 4.01 and XHTML 1.0, however +specify class as CDATA. HTML 5 effectively defines it as CDATA, but +with the additional constraint that each name should be unique (this is not +explicitly outlined in previous specifications). +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt new file mode 100644 index 0000000000..533165e175 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt @@ -0,0 +1,11 @@ +Attr.DefaultImageAlt +TYPE: string/null +DEFAULT: null +VERSION: 3.2.0 +--DESCRIPTION-- +This is the content of the alt tag of an image if the user had not +previously specified an alt attribute. This applies to all images without +a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which +only applies to invalid images, and overrides in the case of an invalid image. +Default behavior with null is to use the basename of the src tag for the alt. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt new file mode 100644 index 0000000000..9eb7e38469 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt @@ -0,0 +1,9 @@ +Attr.DefaultInvalidImage +TYPE: string +DEFAULT: '' +--DESCRIPTION-- +This is the default image an img tag will be pointed to if it does not have +a valid src attribute. In future versions, we may allow the image tag to +be removed completely, but due to design issues, this is not possible right +now. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt new file mode 100644 index 0000000000..2f17bf477a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt @@ -0,0 +1,8 @@ +Attr.DefaultInvalidImageAlt +TYPE: string +DEFAULT: 'Invalid image' +--DESCRIPTION-- +This is the content of the alt tag of an invalid image if the user had not +previously specified an alt attribute. It has no effect when the image is +valid but there was no alt attribute present. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt new file mode 100644 index 0000000000..52654b53ae --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt @@ -0,0 +1,10 @@ +Attr.DefaultTextDir +TYPE: string +DEFAULT: 'ltr' +--DESCRIPTION-- +Defines the default text direction (ltr or rtl) of the document being +parsed. This generally is the same as the value of the dir attribute in +HTML, or ltr if that is not specified. +--ALLOWED-- +'ltr', 'rtl' +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt new file mode 100644 index 0000000000..6440d21032 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt @@ -0,0 +1,16 @@ +Attr.EnableID +TYPE: bool +DEFAULT: false +VERSION: 1.2.0 +--DESCRIPTION-- +Allows the ID attribute in HTML. This is disabled by default due to the +fact that without proper configuration user input can easily break the +validation of a webpage by specifying an ID that is already on the +surrounding HTML. If you don't mind throwing caution to the wind, enable +this directive, but I strongly recommend you also consider blacklisting IDs +you use (%Attr.IDBlacklist) or prefixing all user supplied IDs +(%Attr.IDPrefix). When set to true HTML Purifier reverts to the behavior of +pre-1.2.0 versions. +--ALIASES-- +HTML.EnableAttrID +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt new file mode 100644 index 0000000000..f31d226f58 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt @@ -0,0 +1,8 @@ +Attr.ForbiddenClasses +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array() +--DESCRIPTION-- +List of forbidden class values in the class attribute. By default, this is +empty, which means that no classes are forbidden. See also %Attr.AllowedClasses. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt new file mode 100644 index 0000000000..735d4b7a10 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt @@ -0,0 +1,10 @@ +Attr.ID.HTML5 +TYPE: bool/null +DEFAULT: null +VERSION: 4.8.0 +--DESCRIPTION-- +In HTML5, restrictions on the format of the id attribute have been significantly +relaxed, such that any string is valid so long as it contains no spaces and +is at least one character. In lieu of a general HTML5 compatibility flag, +set this configuration directive to true to use the relaxed rules. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt new file mode 100644 index 0000000000..5f2b5e3d2c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt @@ -0,0 +1,5 @@ +Attr.IDBlacklist +TYPE: list +DEFAULT: array() +DESCRIPTION: Array of IDs not allowed in the document. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt new file mode 100644 index 0000000000..6f5824586e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt @@ -0,0 +1,9 @@ +Attr.IDBlacklistRegexp +TYPE: string/null +VERSION: 1.6.0 +DEFAULT: NULL +--DESCRIPTION-- +PCRE regular expression to be matched against all IDs. If the expression is +matches, the ID is rejected. Use this with care: may cause significant +degradation. ID matching is done after all other validation. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt new file mode 100644 index 0000000000..cc49d43fd0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt @@ -0,0 +1,12 @@ +Attr.IDPrefix +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +String to prefix to IDs. If you have no idea what IDs your pages may use, +you may opt to simply add a prefix to all user-submitted ID attributes so +that they are still usable, but will not conflict with core page IDs. +Example: setting the directive to 'user_' will result in a user submitted +'foo' to become 'user_foo' Be sure to set %HTML.EnableAttrID to true +before using this. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt new file mode 100644 index 0000000000..2c5924a7ad --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt @@ -0,0 +1,14 @@ +Attr.IDPrefixLocal +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +Temporary prefix for IDs used in conjunction with %Attr.IDPrefix. If you +need to allow multiple sets of user content on web page, you may need to +have a seperate prefix that changes with each iteration. This way, +seperately submitted user content displayed on the same page doesn't +clobber each other. Ideal values are unique identifiers for the content it +represents (i.e. the id of the row in the database). Be sure to add a +seperator (like an underscore) at the end. Warning: this directive will +not work unless %Attr.IDPrefix is set to a non-empty value! +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt new file mode 100644 index 0000000000..d5caa1bb97 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt @@ -0,0 +1,31 @@ +AutoFormat.AutoParagraph +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +

+
    +
  • Always applies to inline elements or text in the root node,
  • +
  • Applies to inline elements or text with double newlines in nodes + that allow paragraph tags,
  • +
  • Applies to double newlines in paragraph tags
  • +
+

+ p tags must be allowed for this directive to take effect. + We do not use br tags for paragraphing, as that is + semantically incorrect. +

+

+ To prevent auto-paragraphing as a content-producer, refrain from using + double-newlines except to specify a new paragraph or in contexts where + it has special meaning (whitespace usually has no meaning except in + tags like pre, so this should not be difficult.) To prevent + the paragraphing of inline text adjacent to block elements, wrap them + in div tags (the behavior is slightly different outside of + the root node.) +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt new file mode 100644 index 0000000000..2a476481af --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt @@ -0,0 +1,12 @@ +AutoFormat.Custom +TYPE: list +VERSION: 2.0.1 +DEFAULT: array() +--DESCRIPTION-- + +

+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100644 index 0000000000..663064a344 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100644 index 0000000000..3a48ba960e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on linkification, auto-linking http, ftp and + https URLs. a tags with the href attribute + must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt new file mode 100644 index 0000000000..db58b13464 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify.DocURL +TYPE: string +VERSION: 2.0.1 +DEFAULT: '#%s' +ALIASES: AutoFormatParam.PurifierLinkifyDocURL +--DESCRIPTION-- +

+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100644 index 0000000000..7996488be0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ Internal auto-formatter that converts configuration directives in + syntax %Namespace.Directive to links. a tags + with the href attribute must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt new file mode 100644 index 0000000000..6367fe23c9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt @@ -0,0 +1,14 @@ +AutoFormat.RemoveEmpty.Predicate +TYPE: hash +VERSION: 4.7.0 +DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src')) +--DESCRIPTION-- +

+ Given that an element has no contents, it will be removed by default, unless + this predicate dictates otherwise. The predicate can either be an associative + map from tag name to list of attributes that must be present for the element + to be considered preserved: thus, the default always preserves colgroup, + th and td, and also iframe if it + has a src. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt new file mode 100644 index 0000000000..35c393b4e6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array('td' => true, 'th' => true) +--DESCRIPTION-- +

+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100644 index 0000000000..9228dee228 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoFormat.RemoveEmpty is enabled. +

+

+ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100644 index 0000000000..34657ba47b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +

+
  • + Tags with no attributes and no content, and that are not empty + elements (remove <a></a> but not + <br />), and +
  • +
  • + Tags with no content, except for:
      +
    • The colgroup element, or
    • +
    • + Elements with the id or name attribute, + when those attributes are permitted on those elements. +
    • +
  • +
+

+ Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +

+

+ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +

+

+ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt new file mode 100644 index 0000000000..dde990ab26 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveSpansWithoutAttributes +TYPE: bool +VERSION: 4.0.1 +DEFAULT: false +--DESCRIPTION-- +

+ This directive causes span tags without any attributes + to be removed. It will also remove spans that had all attributes + removed during processing. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt new file mode 100644 index 0000000000..4d054b1f07 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt @@ -0,0 +1,11 @@ +CSS.AllowDuplicates +TYPE: bool +DEFAULT: false +VERSION: 4.8.0 +--DESCRIPTION-- +

+ By default, HTML Purifier removes duplicate CSS properties, + like color:red; color:blue. If this is set to + true, duplicate properties are allowed. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt new file mode 100644 index 0000000000..b324608f76 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt @@ -0,0 +1,8 @@ +CSS.AllowImportant +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not !important cascade modifiers should +be allowed in user CSS. If false, !important will stripped. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt new file mode 100644 index 0000000000..748be0eec8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt @@ -0,0 +1,11 @@ +CSS.AllowTricky +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not to allow "tricky" CSS properties and +values. Tricky CSS properties/values can drastically modify page layout or +be used for deceptive practices but do not directly constitute a security risk. +For example, display:none; is considered a tricky property that +will only be allowed if this directive is set to true. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt new file mode 100644 index 0000000000..3fd4654065 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt @@ -0,0 +1,12 @@ +CSS.AllowedFonts +TYPE: lookup/null +VERSION: 4.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ Allows you to manually specify a set of allowed fonts. If + NULL, all fonts are allowed. This directive + affects generic names (serif, sans-serif, monospace, cursive, + fantasy) as well as specific font families. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt new file mode 100644 index 0000000000..460112ebe0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt @@ -0,0 +1,18 @@ +CSS.AllowedProperties +TYPE: lookup/null +VERSION: 3.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100644 index 0000000000..5cb7dda3ba --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt new file mode 100644 index 0000000000..f1f5c5f12b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt @@ -0,0 +1,13 @@ +CSS.ForbiddenProperties +TYPE: lookup +VERSION: 4.2.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This is the logical inverse of %CSS.AllowedProperties, and it will + override that directive or any other directive. If possible, + %CSS.AllowedProperties is recommended over this directive, + because it can sometimes be difficult to tell whether or not you've + forbidden all of the CSS properties you truly would like to disallow. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100644 index 0000000000..7a3291470c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This parameter sets the maximum allowed length on img tags, + effectively the width and height properties. + Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %HTML.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the CSS max is a number with + a unit). +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt new file mode 100644 index 0000000000..148eedb8be --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt @@ -0,0 +1,10 @@ +CSS.Proprietary +TYPE: bool +VERSION: 3.0.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Whether or not to allow safe, proprietary CSS values. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt new file mode 100644 index 0000000000..e733a61e8a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt @@ -0,0 +1,9 @@ +CSS.Trusted +TYPE: bool +VERSION: 4.2.1 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user's CSS input is trusted or not. If the +input is trusted, a more expansive set of allowed properties. See +also %HTML.Trusted. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100644 index 0000000000..c486724c88 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100644 index 0000000000..54036507d6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt new file mode 100644 index 0000000000..2e0cc81044 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt @@ -0,0 +1,16 @@ +Cache.SerializerPermissions +TYPE: int/null +VERSION: 4.3.0 +DEFAULT: 0755 +--DESCRIPTION-- + +

+ Directory permissions of the files and directories created inside + the DefinitionCache/Serializer or other custom serializer path. +

+

+ In HTML Purifier 4.8.0, this also supports NULL, + which means that no chmod'ing or directory creation shall + occur. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt new file mode 100644 index 0000000000..568cbf3b32 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt @@ -0,0 +1,18 @@ +Core.AggressivelyFixLt +TYPE: bool +VERSION: 2.1.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +

+

+ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt new file mode 100644 index 0000000000..b2b6ab1496 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt @@ -0,0 +1,16 @@ +Core.AggressivelyRemoveScript +TYPE: bool +VERSION: 4.9.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter removal of + script tags. This is not necessary for security, + but it can help work around a bug in libxml where embedded + HTML elements inside script sections cause the parser to + choke. To revert to pre-4.9.0 behavior, set this to false. + This directive has no effect if %Core.Trusted is true, + %Core.RemoveScriptContents is false, or %Core.HiddenElements + does not contain script. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt new file mode 100644 index 0000000000..2c910cc7de --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt @@ -0,0 +1,16 @@ +Core.AllowHostnameUnderscore +TYPE: bool +VERSION: 4.6.0 +DEFAULT: false +--DESCRIPTION-- +

+ By RFC 1123, underscores are not permitted in host names. + (This is in contrast to the specification for DNS, RFC + 2181, which allows underscores.) + However, most browsers do the right thing when faced with + an underscore in the host name, and so some poorly written + websites are written with the expectation this should work. + Setting this parameter to true relaxes our allowed character + check so that underscores are permitted. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt new file mode 100644 index 0000000000..06278f82a1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt @@ -0,0 +1,12 @@ +Core.AllowParseManyTags +TYPE: bool +DEFAULT: false +VERSION: 4.10.1 +--DESCRIPTION-- +

+ This directive allows parsing of many nested tags. + If you set true, relaxes any hardcoded limit from the parser. + However, in that case it may cause a Dos attack. + Be careful when enabling it. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100644 index 0000000000..d7317911fa --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100644 index 0000000000..a75844cd58 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,160 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'aliceblue' => '#F0F8FF', + 'antiquewhite' => '#FAEBD7', + 'aqua' => '#00FFFF', + 'aquamarine' => '#7FFFD4', + 'azure' => '#F0FFFF', + 'beige' => '#F5F5DC', + 'bisque' => '#FFE4C4', + 'black' => '#000000', + 'blanchedalmond' => '#FFEBCD', + 'blue' => '#0000FF', + 'blueviolet' => '#8A2BE2', + 'brown' => '#A52A2A', + 'burlywood' => '#DEB887', + 'cadetblue' => '#5F9EA0', + 'chartreuse' => '#7FFF00', + 'chocolate' => '#D2691E', + 'coral' => '#FF7F50', + 'cornflowerblue' => '#6495ED', + 'cornsilk' => '#FFF8DC', + 'crimson' => '#DC143C', + 'cyan' => '#00FFFF', + 'darkblue' => '#00008B', + 'darkcyan' => '#008B8B', + 'darkgoldenrod' => '#B8860B', + 'darkgray' => '#A9A9A9', + 'darkgrey' => '#A9A9A9', + 'darkgreen' => '#006400', + 'darkkhaki' => '#BDB76B', + 'darkmagenta' => '#8B008B', + 'darkolivegreen' => '#556B2F', + 'darkorange' => '#FF8C00', + 'darkorchid' => '#9932CC', + 'darkred' => '#8B0000', + 'darksalmon' => '#E9967A', + 'darkseagreen' => '#8FBC8F', + 'darkslateblue' => '#483D8B', + 'darkslategray' => '#2F4F4F', + 'darkslategrey' => '#2F4F4F', + 'darkturquoise' => '#00CED1', + 'darkviolet' => '#9400D3', + 'deeppink' => '#FF1493', + 'deepskyblue' => '#00BFFF', + 'dimgray' => '#696969', + 'dimgrey' => '#696969', + 'dodgerblue' => '#1E90FF', + 'firebrick' => '#B22222', + 'floralwhite' => '#FFFAF0', + 'forestgreen' => '#228B22', + 'fuchsia' => '#FF00FF', + 'gainsboro' => '#DCDCDC', + 'ghostwhite' => '#F8F8FF', + 'gold' => '#FFD700', + 'goldenrod' => '#DAA520', + 'gray' => '#808080', + 'grey' => '#808080', + 'green' => '#008000', + 'greenyellow' => '#ADFF2F', + 'honeydew' => '#F0FFF0', + 'hotpink' => '#FF69B4', + 'indianred' => '#CD5C5C', + 'indigo' => '#4B0082', + 'ivory' => '#FFFFF0', + 'khaki' => '#F0E68C', + 'lavender' => '#E6E6FA', + 'lavenderblush' => '#FFF0F5', + 'lawngreen' => '#7CFC00', + 'lemonchiffon' => '#FFFACD', + 'lightblue' => '#ADD8E6', + 'lightcoral' => '#F08080', + 'lightcyan' => '#E0FFFF', + 'lightgoldenrodyellow' => '#FAFAD2', + 'lightgray' => '#D3D3D3', + 'lightgrey' => '#D3D3D3', + 'lightgreen' => '#90EE90', + 'lightpink' => '#FFB6C1', + 'lightsalmon' => '#FFA07A', + 'lightseagreen' => '#20B2AA', + 'lightskyblue' => '#87CEFA', + 'lightslategray' => '#778899', + 'lightslategrey' => '#778899', + 'lightsteelblue' => '#B0C4DE', + 'lightyellow' => '#FFFFE0', + 'lime' => '#00FF00', + 'limegreen' => '#32CD32', + 'linen' => '#FAF0E6', + 'magenta' => '#FF00FF', + 'maroon' => '#800000', + 'mediumaquamarine' => '#66CDAA', + 'mediumblue' => '#0000CD', + 'mediumorchid' => '#BA55D3', + 'mediumpurple' => '#9370DB', + 'mediumseagreen' => '#3CB371', + 'mediumslateblue' => '#7B68EE', + 'mediumspringgreen' => '#00FA9A', + 'mediumturquoise' => '#48D1CC', + 'mediumvioletred' => '#C71585', + 'midnightblue' => '#191970', + 'mintcream' => '#F5FFFA', + 'mistyrose' => '#FFE4E1', + 'moccasin' => '#FFE4B5', + 'navajowhite' => '#FFDEAD', + 'navy' => '#000080', + 'oldlace' => '#FDF5E6', + 'olive' => '#808000', + 'olivedrab' => '#6B8E23', + 'orange' => '#FFA500', + 'orangered' => '#FF4500', + 'orchid' => '#DA70D6', + 'palegoldenrod' => '#EEE8AA', + 'palegreen' => '#98FB98', + 'paleturquoise' => '#AFEEEE', + 'palevioletred' => '#DB7093', + 'papayawhip' => '#FFEFD5', + 'peachpuff' => '#FFDAB9', + 'peru' => '#CD853F', + 'pink' => '#FFC0CB', + 'plum' => '#DDA0DD', + 'powderblue' => '#B0E0E6', + 'purple' => '#800080', + 'rebeccapurple' => '#663399', + 'red' => '#FF0000', + 'rosybrown' => '#BC8F8F', + 'royalblue' => '#4169E1', + 'saddlebrown' => '#8B4513', + 'salmon' => '#FA8072', + 'sandybrown' => '#F4A460', + 'seagreen' => '#2E8B57', + 'seashell' => '#FFF5EE', + 'sienna' => '#A0522D', + 'silver' => '#C0C0C0', + 'skyblue' => '#87CEEB', + 'slateblue' => '#6A5ACD', + 'slategray' => '#708090', + 'slategrey' => '#708090', + 'snow' => '#FFFAFA', + 'springgreen' => '#00FF7F', + 'steelblue' => '#4682B4', + 'tan' => '#D2B48C', + 'teal' => '#008080', + 'thistle' => '#D8BFD8', + 'tomato' => '#FF6347', + 'turquoise' => '#40E0D0', + 'violet' => '#EE82EE', + 'wheat' => '#F5DEB3', + 'white' => '#FFFFFF', + 'whitesmoke' => '#F5F5F5', + 'yellow' => '#FFFF00', + 'yellowgreen' => '#9ACD32' +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. The lookup +is done in a case-insensitive manner. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100644 index 0000000000..64b114fce2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100644 index 0000000000..36f16e07ea --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + +

+ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt new file mode 100644 index 0000000000..1cd4c2c964 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt @@ -0,0 +1,14 @@ +Core.DisableExcludes +TYPE: bool +DEFAULT: false +VERSION: 4.5.0 +--DESCRIPTION-- +

+ This directive disables SGML-style exclusions, e.g. the exclusion of + <object> in any descendant of a + <pre> tag. Disabling excludes will allow some + invalid documents to pass through HTML Purifier, but HTML Purifier + will also be less likely to accidentally remove large documents during + processing. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt new file mode 100644 index 0000000000..ce243c35dc --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt @@ -0,0 +1,9 @@ +Core.EnableIDNA +TYPE: bool +DEFAULT: false +VERSION: 4.4.0 +--DESCRIPTION-- +Allows international domain names in URLs. This configuration option +requires the PEAR Net_IDNA2 module to be installed. It operates by +punycoding any internationalized host names for maximum portability. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt new file mode 100644 index 0000000000..8bfb47c3ac --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt @@ -0,0 +1,15 @@ +Core.Encoding +TYPE: istring +DEFAULT: 'utf-8' +--DESCRIPTION-- +If for some reason you are unable to convert all webpages to UTF-8, you can +use this directive as a stop-gap compatibility change to let HTML Purifier +deal with non UTF-8 input. This technique has notable deficiencies: +absolutely no characters outside of the selected character encoding will be +preserved, not even the ones that have been ampersand escaped (this is due +to a UTF-8 specific feature that automatically resolves all +entities), making it pretty useless for anything except the most I18N-blind +applications, although %Core.EscapeNonASCIICharacters offers fixes this +trouble with another tradeoff. This directive only accepts ISO-8859-1 if +iconv is not enabled. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt new file mode 100644 index 0000000000..a3881be75c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt @@ -0,0 +1,12 @@ +Core.EscapeInvalidChildren +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +

Warning: this configuration option is no longer does anything as of 4.6.0.

+ +

When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes.

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100644 index 0000000000..a7a5b249bb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100644 index 0000000000..abb499948a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100644 index 0000000000..915391edb7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +

+ This directive is a lookup array of elements which should have their + contents removed when they are not allowed by the HTML definition. + For example, the contents of a script tag are not + normally shown in a document, so if script tags are to be removed, + their contents should be removed to. This is opposed to a b + tag, which defines some presentational changes but does not hide its + contents. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt new file mode 100644 index 0000000000..233fca14f8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt @@ -0,0 +1,10 @@ +Core.Language +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'en' +--DESCRIPTION-- + +ISO 639 language code for localizable things in HTML Purifier to use, +which is mainly error reporting. There is currently only an English (en) +translation, so this directive is currently useless. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt new file mode 100644 index 0000000000..392b436493 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt @@ -0,0 +1,36 @@ +Core.LegacyEntityDecoder +TYPE: bool +VERSION: 4.9.0 +DEFAULT: false +--DESCRIPTION-- +

+ Prior to HTML Purifier 4.9.0, entities were decoded by performing + a global search replace for all entities whose decoded versions + did not have special meanings under HTML, and replaced them with + their decoded versions. We would match all entities, even if they did + not have a trailing semicolon, but only if there weren't any trailing + alphanumeric characters. +

+
+ + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena&yena&yena
&yen=¥=¥=
+

+ In HTML Purifier 4.9.0, we changed the behavior of entity parsing + to match entities that had missing trailing semicolons in less + cases, to more closely match HTML5 parsing behavior: +

+ + + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena¥a&yena
&yen=¥=&yen=
+

+ This flag reverts back to pre-HTML Purifier 4.9.0 behavior. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt new file mode 100644 index 0000000000..8983e2cca9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt @@ -0,0 +1,34 @@ +Core.LexerImpl +TYPE: mixed/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This parameter determines what lexer implementation can be used. The + valid values are: +

+
+
null
+
+ Recommended, the lexer implementation will be auto-detected based on + your PHP-version and configuration. +
+
string lexer identifier
+
+ This is a slim way of manually overridding the implementation. + Currently recognized values are: DOMLex (the default PHP5 +implementation) + and DirectLex (the default PHP4 implementation). Only use this if + you know what you are doing: usually, the auto-detection will + manage things for cases you aren't even aware of. +
+
object lexer instance
+
+ Super-advanced: you can specify your own, custom, implementation that + implements the interface defined by HTMLPurifier_Lexer. + I may remove this option simply because I don't expect anyone + to use it. +
+
+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt new file mode 100644 index 0000000000..eb841a7597 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt @@ -0,0 +1,16 @@ +Core.MaintainLineNumbers +TYPE: bool/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt new file mode 100644 index 0000000000..d77f5360d7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt @@ -0,0 +1,11 @@ +Core.NormalizeNewlines +TYPE: bool +VERSION: 4.2.0 +DEFAULT: true +--DESCRIPTION-- +

+ Whether or not to normalize newlines to the operating + system default. When false, HTML Purifier + will attempt to preserve mixed newline files. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt new file mode 100644 index 0000000000..95e5285ca6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt @@ -0,0 +1,10 @@ +Core.RemoveBlanks +TYPE: bool +DEFAULT: false +VERSION: 4.18 +--DESCRIPTION-- +

+ If set to true, blank nodes will be removed. This can be useful for maintaining + backwards compatibility when upgrading from previous versions of PHP. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt new file mode 100644 index 0000000000..4070c2a0de --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt @@ -0,0 +1,12 @@ +Core.RemoveInvalidImg +TYPE: bool +DEFAULT: true +VERSION: 1.3.0 +--DESCRIPTION-- + +

+ This directive enables pre-emptive URI checking in img + tags, as the attribute validation strategy is not authorized to + remove elements from the document. Revert to pre-1.3.0 behavior by setting to false. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt new file mode 100644 index 0000000000..3397d9f71f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt @@ -0,0 +1,11 @@ +Core.RemoveProcessingInstructions +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +Instead of escaping processing instructions in the form <? ... +?>, remove it out-right. This may be useful if the HTML +you are validating contains XML processing instruction gunk, however, +it can also be user-unfriendly for people attempting to post PHP +snippets. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt new file mode 100644 index 0000000000..a4cd966df8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt @@ -0,0 +1,12 @@ +Core.RemoveScriptContents +TYPE: bool/null +DEFAULT: NULL +VERSION: 2.0.0 +DEPRECATED-VERSION: 2.1.0 +DEPRECATED-USE: Core.HiddenElements +--DESCRIPTION-- +

+ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100644 index 0000000000..3db50ef204 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This directive can be used to add custom filters; it is nearly the + equivalent of the now deprecated HTMLPurifier->addFilter() + method. Specify an array of concrete implementations. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt new file mode 100644 index 0000000000..16829bcda0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt @@ -0,0 +1,14 @@ +Filter.ExtractStyleBlocks.Escaping +TYPE: bool +VERSION: 3.0.0 +DEFAULT: true +ALIASES: Filter.ExtractStyleBlocksEscaping, FilterParam.ExtractStyleBlocksEscaping +--DESCRIPTION-- + +

+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100644 index 0000000000..7f95f54d12 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +

+ If you would like users to be able to define external stylesheets, but + only allow them to specify CSS declarations for a specific node and + prevent them from fiddling with other elements, use this directive. + It accepts any valid CSS selector, and will prepend this to any + CSS declaration extracted from the document. For example, if this + directive is set to #user-content and a user uses the + selector a:hover, the final selector will be + #user-content a:hover. +

+

+ The comma shorthand may be used; consider the above example, with + #user-content, #user-content2, the final selector will + be #user-content a:hover, #user-content2 a:hover. +

+

+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100644 index 0000000000..6c231b2d7f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +

+ If left NULL, HTML Purifier will attempt to instantiate a csstidy + class to use for internal cleaning. This will usually be good enough. +

+

+ However, for trusted user input, you can set this to false to + disable cleaning. In addition, you can supply your own concrete implementation + of Tidy's interface to use, although I don't know why you'd want to do that. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt new file mode 100644 index 0000000000..078d087417 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt @@ -0,0 +1,74 @@ +Filter.ExtractStyleBlocks +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +EXTERNAL: CSSTidy +--DESCRIPTION-- +

+ This directive turns on the style block extraction filter, which removes + style blocks from input HTML, cleans them up with CSSTidy, + and places them in the StyleBlocks context variable, for further + use by you, usually to be placed in an external stylesheet, or a + style block in the head of your document. +

+

+ Sample usage: +

+
';
+?>
+
+
+
+  Filter.ExtractStyleBlocks
+body {color:#F00;} Some text';
+
+    $config = HTMLPurifier_Config::createDefault();
+    $config->set('Filter', 'ExtractStyleBlocks', true);
+    $purifier = new HTMLPurifier($config);
+
+    $html = $purifier->purify($dirty);
+
+    // This implementation writes the stylesheets to the styles/ directory.
+    // You can also echo the styles inside the document, but it's a bit
+    // more difficult to make sure they get interpreted properly by
+    // browsers; try the usual CSS armoring techniques.
+    $styles = $purifier->context->get('StyleBlocks');
+    $dir = 'styles/';
+    if (!is_dir($dir)) mkdir($dir);
+    $hash = sha1($_GET['html']);
+    foreach ($styles as $i => $style) {
+        file_put_contents($name = $dir . $hash . "_$i");
+        echo '';
+    }
+?>
+
+
+  
+ +
+ + +]]>
+

+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100644 index 0000000000..321eaa2d80 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,16 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Warning: Deprecated in favor of %HTML.SafeObject and + %Output.FlashCompat (turn both on to allow YouTube videos and other + Flash content). +

+

+ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100644 index 0000000000..0b2c106da5 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,25 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This is a preferred convenience directive that combines + %HTML.AllowedElements and %HTML.AllowedAttributes. + Specify elements and attributes that are allowed using: + element1[attr1|attr2],element2.... For example, + if you would like to only allow paragraphs and links, specify + a[href],p. You can specify attributes that apply + to all elements using an asterisk, e.g. *[lang]. + You can also use newlines instead of commas to separate elements. +

+

+ Warning: + All of the constraints on the component directives are still enforced. + The syntax is a subset of TinyMCE's valid_elements + whitelist: directly copy-pasting it here will probably result in + broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes + are set, this directive has no effect. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt new file mode 100644 index 0000000000..fcf093f17d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt @@ -0,0 +1,19 @@ +HTML.AllowedAttributes +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt new file mode 100644 index 0000000000..140e21423e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt @@ -0,0 +1,10 @@ +HTML.AllowedComments +TYPE: lookup +VERSION: 4.4.0 +DEFAULT: array() +--DESCRIPTION-- +A whitelist which indicates what explicit comment bodies should be +allowed, modulo leading and trailing whitespace. See also %HTML.AllowedCommentsRegexp +(these directives are union'ed together, so a comment is considered +valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt new file mode 100644 index 0000000000..f22e977d43 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt @@ -0,0 +1,15 @@ +HTML.AllowedCommentsRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +A regexp, which if it matches the body of a comment, indicates that +it should be allowed. Trailing and leading spaces are removed prior +to running this regular expression. +Warning: Make sure you specify +correct anchor metacharacters ^regex$, otherwise you may accept +comments that you did not mean to! In particular, the regex /foo|bar/ +is probably not sufficiently strict, since it also allows foobar. +See also %HTML.AllowedComments (these directives are union'ed together, +so a comment is considered valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt new file mode 100644 index 0000000000..1d3fa7907d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt @@ -0,0 +1,23 @@ +HTML.AllowedElements +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ If HTML Purifier's tag set is unsatisfactory for your needs, you can + overload it with your own list of tags to allow. If you change + this, you probably also want to change %HTML.AllowedAttributes; see + also %HTML.Allowed which lets you set allowed elements and + attributes at the same time. +

+

+ If you attempt to allow an element that HTML Purifier does not know + about, HTML Purifier will raise an error. You will need to manually + tell HTML Purifier about this element by using the + advanced customization features. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100644 index 0000000000..5a59a55c08 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +

+

+ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100644 index 0000000000..151fb7b826 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100644 index 0000000000..45ae469ec9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + +

+ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +

+

+ Example: by default value, + <blockquote>Foo</blockquote> would become + <blockquote><p>Foo</p></blockquote>. + The <p> tags can be replaced with whatever you desire, + as long as it is a block level element. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt new file mode 100644 index 0000000000..5246188795 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt @@ -0,0 +1,23 @@ +HTML.CoreModules +TYPE: lookup +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'Structure' => true, + 'Text' => true, + 'Hypertext' => true, + 'List' => true, + 'NonXMLCommonAttributes' => true, + 'XMLCommonAttributes' => true, + 'CommonAttributes' => true, +) +--DESCRIPTION-- + +

+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100644 index 0000000000..6ed70b599f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined their own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100644 index 0000000000..103db754a2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + +

+ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +

+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
+

+ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +

+

+ You must specify a value to this directive to use the + advanced API features. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100644 index 0000000000..229ae0267a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100644 index 0000000000..9dab497f2f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt new file mode 100644 index 0000000000..7878dc0bf6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt @@ -0,0 +1,11 @@ +HTML.FlashAllowFullScreen +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embedded Flash content from + %HTML.SafeObject to expand to the full screen. Corresponds to + the allowFullScreen parameter. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt new file mode 100644 index 0000000000..57358f9bad --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt @@ -0,0 +1,21 @@ +HTML.ForbiddenAttributes +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ While this directive is similar to %HTML.AllowedAttributes, for + forwards-compatibility with XML, this attribute has a different syntax. Instead of + tag.attr, use tag@attr. To disallow href + attributes in a tags, set this directive to + a@href. You can also disallow an attribute globally with + attr or *@attr (either syntax is fine; the latter + is provided for consistency with %HTML.AllowedAttributes). +

+

+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100644 index 0000000000..93a53e14fb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +

+

+ If possible, %HTML.Allowed is recommended over this directive, because it + can sometimes be difficult to tell whether or not you've forbidden all of + the behavior you would like to disallow. If you forbid img + with the expectation of preventing images on your site, you'll be in for + a nasty surprise when people start using the background-image + CSS property. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt new file mode 100644 index 0000000000..4a432d89b7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt @@ -0,0 +1,11 @@ +HTML.Forms +TYPE: bool +VERSION: 4.13.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit form elements in the user input, regardless of + %HTML.Trusted value. Please be very careful when using this functionality, as + enabling forms in untrusted documents may allow for phishing attacks. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt new file mode 100644 index 0000000000..e424c386ec --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt @@ -0,0 +1,14 @@ +HTML.MaxImgLength +TYPE: int/null +DEFAULT: 1200 +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This directive controls the maximum number of pixels in the width and + height attributes in img tags. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %CSS.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the HTML max is an integer). +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt new file mode 100644 index 0000000000..700b30924a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt @@ -0,0 +1,7 @@ +HTML.Nofollow +TYPE: bool +VERSION: 4.3.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, nofollow rel attributes are added to all outgoing links. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt new file mode 100644 index 0000000000..62e8e160c7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt @@ -0,0 +1,12 @@ +HTML.Parent +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'div' +--DESCRIPTION-- + +

+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100644 index 0000000000..dfb720496d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to allow proprietary elements and attributes in your + documents, as per HTMLPurifier_HTMLModule_Proprietary. + Warning: This can cause your documents to stop + validating! +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt new file mode 100644 index 0000000000..cdda09a4c5 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt @@ -0,0 +1,13 @@ +HTML.SafeEmbed +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating; you should + see if you can use %Output.FlashCompat with %HTML.SafeObject instead + first.

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt new file mode 100644 index 0000000000..5eb6ec2b5a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt @@ -0,0 +1,13 @@ +HTML.SafeIframe +TYPE: bool +VERSION: 4.4.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit iframe tags in untrusted documents. This + directive must be accompanied by a whitelist of permitted iframes, + such as %URI.SafeIframeRegexp, otherwise it will fatally error. + This directive has no effect on strict doctypes, as iframes are not + valid. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100644 index 0000000000..ceb342e22b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,13 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You should also enable + %Output.FlashCompat in order to generate Internet Explorer + compatibility code for your object tags. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt new file mode 100644 index 0000000000..5ebc7a19d5 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt @@ -0,0 +1,10 @@ +HTML.SafeScripting +TYPE: lookup +VERSION: 4.5.0 +DEFAULT: array() +--DESCRIPTION-- +

+ Whether or not to permit script tags to external scripts in documents. + Inline scripting is not allowed, and the script must match an explicit whitelist. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100644 index 0000000000..a8b1de56be --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt new file mode 100644 index 0000000000..587a16778b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt @@ -0,0 +1,8 @@ +HTML.TargetBlank +TYPE: bool +VERSION: 4.4.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, target=blank attributes are added to all outgoing links. +(This includes links from an HTTPS version of a page to an HTTP version.) +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt new file mode 100644 index 0000000000..dd514c0def --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt @@ -0,0 +1,10 @@ +--# vim: et sw=4 sts=4 +HTML.TargetNoopener +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noopener rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt new file mode 100644 index 0000000000..cb5a0b0e5e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt @@ -0,0 +1,9 @@ +HTML.TargetNoreferrer +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noreferrer rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt new file mode 100644 index 0000000000..b4c271b7fa --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt @@ -0,0 +1,8 @@ +HTML.TidyAdd +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to add to the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt new file mode 100644 index 0000000000..4186ccd0d1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt @@ -0,0 +1,24 @@ +HTML.TidyLevel +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'medium' +--DESCRIPTION-- + +

General level of cleanliness the Tidy module should enforce. +There are four allowed values:

+
+
none
+
No extra tidying should be done
+
light
+
Only fix elements that would be discarded otherwise due to + lack of support in doctype
+
medium
+
Enforce best practices
+
heavy
+
Transform all deprecated elements and attributes to standards + compliant equivalents
+
+ +--ALLOWED-- +'none', 'light', 'medium', 'heavy' +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt new file mode 100644 index 0000000000..996762bd1d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt @@ -0,0 +1,8 @@ +HTML.TidyRemove +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to remove from the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt new file mode 100644 index 0000000000..1db9237e9e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt @@ -0,0 +1,9 @@ +HTML.Trusted +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user input is trusted or not. If the input is +trusted, a more expansive set of allowed tags and attributes will be used. +See also %CSS.Trusted. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt new file mode 100644 index 0000000000..2a47e384f4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt @@ -0,0 +1,11 @@ +HTML.XHTML +TYPE: bool +DEFAULT: true +VERSION: 1.1.0 +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not output is XHTML 1.0 or HTML 4.01 flavor. +--ALIASES-- +Core.XHTML +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt new file mode 100644 index 0000000000..08921fde70 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt @@ -0,0 +1,10 @@ +Output.CommentScriptContents +TYPE: bool +VERSION: 2.0.0 +DEFAULT: true +--DESCRIPTION-- +Determines whether or not HTML Purifier should attempt to fix up the +contents of script tags for legacy browsers with comments. +--ALIASES-- +Core.CommentScriptContents +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt new file mode 100644 index 0000000000..d6f0d9f295 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt @@ -0,0 +1,15 @@ +Output.FixInnerHTML +TYPE: bool +VERSION: 4.3.0 +DEFAULT: true +--DESCRIPTION-- +

+ If true, HTML Purifier will protect against Internet Explorer's + mishandling of the innerHTML attribute by appending + a space to any attribute that does not contain angled brackets, spaces + or quotes, but contains a backtick. This slightly changes the + semantics of any given attribute, so if this is unacceptable and + you do not use innerHTML on any of your pages, you can + turn this directive off. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt new file mode 100644 index 0000000000..93398e8598 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt @@ -0,0 +1,11 @@ +Output.FlashCompat +TYPE: bool +VERSION: 4.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will generate Internet Explorer compatibility + code for all object code. This is highly recommended if you enable + %HTML.SafeObject. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100644 index 0000000000..79f8ad82cf --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100644 index 0000000000..232b02362a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will sort attributes by name before writing them back + to the document, converting a tag like: <el b="" a="" c="" /> + to <el a="" b="" c="" />. This is a workaround for + a bug in FCKeditor which causes it to swap attributes order, adding noise + to text diffs. If you're not seeing this bug, chances are, you don't need + this directive. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt new file mode 100644 index 0000000000..06bab00a0a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt @@ -0,0 +1,25 @@ +Output.TidyFormat +TYPE: bool +VERSION: 1.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +

+

+ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +

+

+ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +

+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100644 index 0000000000..071bc0295d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100644 index 0000000000..eb97307e20 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,18 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, + 'tel' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +There is also support for the data and file +URI schemes, but they are not enabled by default. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt new file mode 100644 index 0000000000..876f0680cf --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt @@ -0,0 +1,17 @@ +URI.Base +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100644 index 0000000000..834bc08c0b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,15 @@ +URI.DefaultScheme +TYPE: string/null +DEFAULT: 'http' +--DESCRIPTION-- + +

+ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +

+ +

+ Starting with HTML Purifier 4.9.0, the default scheme can be null, in + which case we reject all URIs which do not have explicit schemes. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100644 index 0000000000..f05312ba86 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100644 index 0000000000..80cfea93f7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100644 index 0000000000..71ce025a2d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +

+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100644 index 0000000000..13c122c8ce --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100644 index 0000000000..abcc1efd61 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100644 index 0000000000..f891de4996 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,15 @@ +URI.DisableResources +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +

+

+ Note: While this directive has been available since 1.3.0, + it didn't actually start doing anything until 4.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100644 index 0000000000..ee83b121de --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100644 index 0000000000..0b6df7625d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100644 index 0000000000..4214900a59 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100644 index 0000000000..58c81dcc44 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Munges all browsable (usually http, https and ftp) + absolute URIs into another URI, usually a URI redirection service. + This directive accepts a URI, formatted with a %s where + the url-encoded original URI should be inserted (sample: + http://www.google.com/url?q=%s). +

+

+ Uses for this directive: +

+
    +
  • + Prevent PageRank leaks, while being fairly transparent + to users (you may also want to add some client side JavaScript to + override the text in the statusbar). Notice: + Many security experts believe that this form of protection does not deter spam-bots. +
  • +
  • + Redirect users to a splash page telling them they are leaving your + website. While this is poor usability practice, it is often mandated + in corporate environments. +
  • +
+

+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging + of browsable external resources, which could break things if your redirection + script was a splash page or used meta tags. To revert to + previous behavior, please use %URI.MungeResources. +

+

+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +

+

+ Starting with HTML Purifier 3.1.1, there is also these substitutions: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescriptionExample <a href="">
%r1 - The URI embeds a resource
(blank) - The URI is merely a link
%nThe name of the tag this URI came froma
%mThe name of the attribute this URI came fromhref
%pThe name of the CSS property this URI came from, or blank if irrelevant
+

+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100644 index 0000000000..6fce0fdc37 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ If true, any URI munging directives like %URI.Munge + will also apply to embedded resources, such as <img src="">. + Be careful enabling this directive if you have a redirector script + that does not use the Location HTTP header; all of your images + and other embedded resources will break. +

+

+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100644 index 0000000000..1e17c1d461 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- +

+ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +

+ +
$checksum === hash_hmac("sha256", $url, $secret_key)
+ +

+ If the output is TRUE, the redirector script should accept the URI. +

+ +

+ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +

+ +

+ Remember this has no effect if %URI.Munge is not on. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100644 index 0000000000..23331a4e79 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt new file mode 100644 index 0000000000..79084832be --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt @@ -0,0 +1,22 @@ +URI.SafeIframeRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ A PCRE regular expression that will be matched against an iframe URI. This is + a relatively inflexible scheme, but works well enough for the most common + use-case of iframes: embedded video. This directive only has an effect if + %HTML.SafeIframe is enabled. Here are some example values: +

+
    +
  • %^http://www.youtube.com/embed/% - Allow YouTube videos
  • +
  • %^http://player.vimeo.com/video/% - Allow Vimeo videos
  • +
  • %^http://(www.youtube.com/embed/|player.vimeo.com/video/)% - Allow both
  • +
+

+ Note that this directive does not give you enough granularity to, say, disable + all autoplay videos. Pipe up on the HTML Purifier forums if this + is a capability you want. +

+--# vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini new file mode 100644 index 0000000000..5de4505e1b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini @@ -0,0 +1,3 @@ +name = "HTML Purifier" + +; vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php new file mode 100644 index 0000000000..543e3f8f11 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php @@ -0,0 +1,170 @@ + true) indexed by name. + * @type array + * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets + */ + public $lookup = array(); + + /** + * Synchronized list of defined content sets (keys of info). + * @type array + */ + protected $keys = array(); + /** + * Synchronized list of defined content values (values of info). + * @type array + */ + protected $values = array(); + + /** + * Merges in module's content sets, expands identifiers in the content + * sets and populates the keys, values and lookup member variables. + * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule + */ + public function __construct($modules) + { + if (!is_array($modules)) { + $modules = array($modules); + } + // populate content_sets based on module hints + // sorry, no way of overloading + foreach ($modules as $module) { + foreach ($module->content_sets as $key => $value) { + $temp = $this->convertToLookup($value); + if (isset($this->lookup[$key])) { + // add it into the existing content set + $this->lookup[$key] = array_merge($this->lookup[$key], $temp); + } else { + $this->lookup[$key] = $temp; + } + } + } + $old_lookup = false; + while ($old_lookup !== $this->lookup) { + $old_lookup = $this->lookup; + foreach ($this->lookup as $i => $set) { + $add = array(); + foreach ($set as $element => $x) { + if (isset($this->lookup[$element])) { + $add += $this->lookup[$element]; + unset($this->lookup[$i][$element]); + } + } + $this->lookup[$i] += $add; + } + } + + foreach ($this->lookup as $key => $lookup) { + $this->info[$key] = implode(' | ', array_keys($lookup)); + } + $this->keys = array_keys($this->info); + $this->values = array_values($this->info); + } + + /** + * Accepts a definition; generates and assigns a ChildDef for it + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + */ + public function generateChildDef(&$def, $module) + { + if (!empty($def->child)) { // already done! + return; + } + $content_model = $def->content_model; + if (is_string($content_model)) { + // Assume that $this->keys is alphanumeric + $def->content_model = preg_replace_callback( + '/\b(' . implode('|', $this->keys) . ')\b/', + array($this, 'generateChildDefCallback'), + $content_model + ); + //$def->content_model = str_replace( + // $this->keys, $this->values, $content_model); + } + $def->child = $this->getChildDef($def, $module); + } + + public function generateChildDefCallback($matches) + { + return $this->info[$matches[0]]; + } + + /** + * Instantiates a ChildDef based on content_model and content_model_type + * member variables in HTMLPurifier_ElementDef + * @note This will also defer to modules for custom HTMLPurifier_ChildDef + * subclasses that need content set expansion + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + * @return HTMLPurifier_ChildDef corresponding to ElementDef + */ + public function getChildDef($def, $module) + { + $value = $def->content_model; + if (is_object($value)) { + trigger_error( + 'Literal object child definitions should be stored in '. + 'ElementDef->child not ElementDef->content_model', + E_USER_NOTICE + ); + return $value; + } + switch ($def->content_model_type) { + case 'required': + return new HTMLPurifier_ChildDef_Required($value); + case 'optional': + return new HTMLPurifier_ChildDef_Optional($value); + case 'empty': + return new HTMLPurifier_ChildDef_Empty(); + case 'custom': + return new HTMLPurifier_ChildDef_Custom($value); + } + // defer to its module + $return = false; + if ($module->defines_child_def) { // save a func call + $return = $module->getChildDef($def); + } + if ($return !== false) { + return $return; + } + // error-out + trigger_error( + 'Could not determine which ChildDef class to instantiate', + E_USER_ERROR + ); + return false; + } + + /** + * Converts a string list of elements separated by pipes into + * a lookup array. + * @param string $string List of elements + * @return array Lookup array of elements + */ + protected function convertToLookup($string) + { + $array = explode('|', str_replace(' ', '', $string)); + $ret = array(); + foreach ($array as $k) { + $ret[$k] = true; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php new file mode 100644 index 0000000000..00e509c85c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php @@ -0,0 +1,95 @@ +_storage)) { + trigger_error( + "Name $name produces collision, cannot re-register", + E_USER_ERROR + ); + return; + } + $this->_storage[$name] =& $ref; + } + + /** + * Retrieves a variable reference from the context. + * @param string $name String name + * @param bool $ignore_error Boolean whether or not to ignore error + * @return mixed + */ + public function &get($name, $ignore_error = false) + { + if (!array_key_exists($name, $this->_storage)) { + if (!$ignore_error) { + trigger_error( + "Attempted to retrieve non-existent variable $name", + E_USER_ERROR + ); + } + $var = null; // so we can return by reference + return $var; + } + return $this->_storage[$name]; + } + + /** + * Destroys a variable in the context. + * @param string $name String name + */ + public function destroy($name) + { + if (!array_key_exists($name, $this->_storage)) { + trigger_error( + "Attempted to destroy non-existent variable $name", + E_USER_ERROR + ); + return; + } + unset($this->_storage[$name]); + } + + /** + * Checks whether or not the variable exists. + * @param string $name String name + * @return bool + */ + public function exists($name) + { + return array_key_exists($name, $this->_storage); + } + + /** + * Loads a series of variables from an associative array + * @param array $context_array Assoc array of variables to load + */ + public function loadArray($context_array) + { + foreach ($context_array as $key => $discard) { + $this->register($key, $context_array[$key]); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php new file mode 100644 index 0000000000..bc6d433647 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php @@ -0,0 +1,55 @@ +setup) { + return; + } + $this->setup = true; + $this->doSetup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php new file mode 100644 index 0000000000..9aa8ff354f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php @@ -0,0 +1,129 @@ +type = $type; + } + + /** + * Generates a unique identifier for a particular configuration + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config + * @return string + */ + public function generateKey($config) + { + return $config->version . ',' . // possibly replace with function calls + $config->getBatchSerial($this->type) . ',' . + $config->get($this->type . '.DefinitionRev'); + } + + /** + * Tests whether or not a key is old with respect to the configuration's + * version and revision number. + * @param string $key Key to test + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config to test against + * @return bool + */ + public function isOld($key, $config) + { + if (substr_count($key, ',') < 2) { + return true; + } + list($version, $hash, $revision) = explode(',', $key, 3); + $compare = version_compare($version, $config->version); + // version mismatch, is always old + if ($compare != 0) { + return true; + } + // versions match, ids match, check revision number + if ($hash == $config->getBatchSerial($this->type) && + $revision < $config->get($this->type . '.DefinitionRev')) { + return true; + } + return false; + } + + /** + * Checks if a definition's type jives with the cache's type + * @note Throws an error on failure + * @param HTMLPurifier_Definition $def Definition object to check + * @return bool true if good, false if not + */ + public function checkDefType($def) + { + if ($def->type !== $this->type) { + trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}"); + return false; + } + return true; + } + + /** + * Adds a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function add($def, $config); + + /** + * Unconditionally saves a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function set($def, $config); + + /** + * Replace an object in the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function replace($def, $config); + + /** + * Retrieves a definition object from the cache + * @param HTMLPurifier_Config $config + */ + abstract public function get($config); + + /** + * Removes a definition object to the cache + * @param HTMLPurifier_Config $config + */ + abstract public function remove($config); + + /** + * Clears all objects from cache + * @param HTMLPurifier_Config $config + */ + abstract public function flush($config); + + /** + * Clears all expired (older version or revision) objects from cache + * @note Be careful implementing this method as flush. Flush must + * not interfere with other Definition types, and cleanup() + * should not be repeatedly called by userland code. + * @param HTMLPurifier_Config $config + */ + abstract public function cleanup($config); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php new file mode 100644 index 0000000000..b57a51b6cb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php @@ -0,0 +1,112 @@ +copy(); + // reference is necessary for mocks in PHP 4 + $decorator->cache =& $cache; + $decorator->type = $cache->type; + return $decorator; + } + + /** + * Cross-compatible clone substitute + * @return HTMLPurifier_DefinitionCache_Decorator + */ + public function copy() + { + return new HTMLPurifier_DefinitionCache_Decorator(); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function add($def, $config) + { + return $this->cache->add($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + return $this->cache->set($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + return $this->cache->replace($def, $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + return $this->cache->get($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function remove($config) + { + return $this->cache->remove($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function flush($config) + { + return $this->cache->flush($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function cleanup($config) + { + return $this->cache->cleanup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php new file mode 100644 index 0000000000..4991777ce1 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -0,0 +1,78 @@ +definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + $status = parent::set($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + $status = parent::replace($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + $key = $this->generateKey($config); + if (isset($this->definitions[$key])) { + return $this->definitions[$key]; + } + $this->definitions[$key] = parent::get($config); + return $this->definitions[$key]; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in new file mode 100644 index 0000000000..b1fec8d367 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -0,0 +1,82 @@ +checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function set($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function replace($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool|HTMLPurifier_Config + */ + public function get($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unserialize(file_get_contents($file)); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function remove($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unlink($file); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function flush($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // Apparently, on some versions of PHP, readdir will return + // an empty string if you pass an invalid argument to readdir. + // So you need this test. See #49. + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + unlink($dir . '/' . $filename); + } + closedir($dh); + return true; + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function cleanup($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // See #49 (and above). + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + $key = substr($filename, 0, strlen($filename) - 4); + if ($this->isOld($key, $config)) { + unlink($dir . '/' . $filename); + } + } + closedir($dh); + return true; + } + + /** + * Generates the file path to the serial file corresponding to + * the configuration and definition name + * @param HTMLPurifier_Config $config + * @return string + * @todo Make protected + */ + public function generateFilePath($config) + { + $key = $this->generateKey($config); + return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; + } + + /** + * Generates the path to the directory contain this cache's serial files + * @param HTMLPurifier_Config $config + * @return string + * @note No trailing slash + * @todo Make protected + */ + public function generateDirectoryPath($config) + { + $base = $this->generateBaseDirectoryPath($config); + return $base . '/' . $this->type; + } + + /** + * Generates path to base directory that contains all definition type + * serials + * @param HTMLPurifier_Config $config + * @return mixed|string + * @todo Make protected + */ + public function generateBaseDirectoryPath($config) + { + $base = $config->get('Cache.SerializerPath'); + $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; + return $base; + } + + /** + * Convenience wrapper function for file_put_contents + * @param string $file File name to write to + * @param string $data Data to write into file + * @param HTMLPurifier_Config $config + * @return int|bool Number of bytes written if success, or false if failure. + */ + private function _write($file, $data, $config) + { + $result = file_put_contents($file, $data); + if ($result !== false) { + // set permissions of the new file (no execute) + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod !== null) { + chmod($file, $chmod & 0666); + } + } + return $result; + } + + /** + * Prepares the directory that this type stores the serials in + * @param HTMLPurifier_Config $config + * @return bool True if successful + */ + private function _prepareDir($config) + { + $directory = $this->generateDirectoryPath($config); + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod === null) { + if (!@mkdir($directory) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + return true; + } + if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error( + 'Base directory ' . $base . ' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_WARNING + ); + return false; + } elseif (!$this->_testPermissions($base, $chmod)) { + return false; + } + if (!@mkdir($directory, $chmod) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + if (!$this->_testPermissions($directory, $chmod)) { + return false; + } + } elseif (!$this->_testPermissions($directory, $chmod)) { + return false; + } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + * @param string $dir Directory path + * @param int $chmod Permissions + * @return bool True if directory is writable + */ + private function _testPermissions($dir, $chmod) + { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) { + return true; + } + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error( + 'Directory ' . $dir . ' does not exist', + E_USER_WARNING + ); + return false; + } + if (function_exists('posix_getuid') && $chmod !== null) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + $chmod = $chmod | 0700; + if (chmod($dir, $chmod)) { + return true; + } + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = $chmod | 0070; + } else { + // PHP's probably running as nobody, it is + // not obvious how to fix this (777 is probably + // bad if you are multi-user), let the user figure it out + $chmod = null; + } + trigger_error( + 'Directory ' . $dir . ' not writable. ' . + ($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)), + E_USER_WARNING + ); + } else { + // generic error message + trigger_error( + 'Directory ' . $dir . ' not writable, ' . + 'please alter file permissions', + E_USER_WARNING + ); + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100755 index 0000000000..2e35c1c3d0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php new file mode 100644 index 0000000000..3a0f4616a9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php @@ -0,0 +1,106 @@ + array()); + + /** + * @type array + */ + protected $implementations = array(); + + /** + * @type HTMLPurifier_DefinitionCache_Decorator[] + */ + protected $decorators = array(); + + /** + * Initialize default decorators + */ + public function setup() + { + $this->addDecorator('Cleanup'); + } + + /** + * Retrieves an instance of global definition cache factory. + * @param HTMLPurifier_DefinitionCacheFactory $prototype + * @return HTMLPurifier_DefinitionCacheFactory + */ + public static function instance($prototype = null) + { + static $instance; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype === true) { + $instance = new HTMLPurifier_DefinitionCacheFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Registers a new definition cache object + * @param string $short Short name of cache object, for reference + * @param string $long Full class name of cache object, for construction + */ + public function register($short, $long) + { + $this->implementations[$short] = $long; + } + + /** + * Factory method that creates a cache object based on configuration + * @param string $type Name of definitions handled by cache + * @param HTMLPurifier_Config $config Config instance + * @return mixed + */ + public function create($type, $config) + { + $method = $config->get('Cache.DefinitionImpl'); + if ($method === null) { + return new HTMLPurifier_DefinitionCache_Null($type); + } + if (!empty($this->caches[$method][$type])) { + return $this->caches[$method][$type]; + } + if (isset($this->implementations[$method]) && + class_exists($class = $this->implementations[$method])) { + $cache = new $class($type); + } else { + if ($method != 'Serializer') { + trigger_error("Unrecognized DefinitionCache $method, using Serializer instead", E_USER_WARNING); + } + $cache = new HTMLPurifier_DefinitionCache_Serializer($type); + } + foreach ($this->decorators as $decorator) { + $new_cache = $decorator->decorate($cache); + // prevent infinite recursion in PHP 4 + unset($cache); + $cache = $new_cache; + } + $this->caches[$method][$type] = $cache; + return $this->caches[$method][$type]; + } + + /** + * Registers a decorator to add to all new cache objects + * @param HTMLPurifier_DefinitionCache_Decorator|string $decorator An instance or the name of a decorator + */ + public function addDecorator($decorator) + { + if (is_string($decorator)) { + $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator"; + $decorator = new $class; + } + $this->decorators[$decorator->name] = $decorator; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php new file mode 100644 index 0000000000..4acd06e5bd --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php @@ -0,0 +1,73 @@ +renderDoctype. + * If structure changes, please update that function. + */ +class HTMLPurifier_Doctype +{ + /** + * Full name of doctype + * @type string + */ + public $name; + + /** + * List of standard modules (string identifiers or literal objects) + * that this doctype uses + * @type array + */ + public $modules = array(); + + /** + * List of modules to use for tidying up code + * @type array + */ + public $tidyModules = array(); + + /** + * Is the language derived from XML (i.e. XHTML)? + * @type bool + */ + public $xml = true; + + /** + * List of aliases for this doctype + * @type array + */ + public $aliases = array(); + + /** + * Public DTD identifier + * @type string + */ + public $dtdPublic; + + /** + * System DTD identifier + * @type string + */ + public $dtdSystem; + + public function __construct( + $name = null, + $xml = true, + $modules = array(), + $tidyModules = array(), + $aliases = array(), + $dtd_public = null, + $dtd_system = null + ) { + $this->name = $name; + $this->xml = $xml; + $this->modules = $modules; + $this->tidyModules = $tidyModules; + $this->aliases = $aliases; + $this->dtdPublic = $dtd_public; + $this->dtdSystem = $dtd_system; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php new file mode 100644 index 0000000000..acc1d64a62 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php @@ -0,0 +1,142 @@ +doctypes[$doctype->name] = $doctype; + $name = $doctype->name; + // hookup aliases + foreach ($doctype->aliases as $alias) { + if (isset($this->doctypes[$alias])) { + continue; + } + $this->aliases[$alias] = $name; + } + // remove old aliases + if (isset($this->aliases[$name])) { + unset($this->aliases[$name]); + } + return $doctype; + } + + /** + * Retrieves reference to a doctype of a certain name + * @note This function resolves aliases + * @note When possible, use the more fully-featured make() + * @param string $doctype Name of doctype + * @return HTMLPurifier_Doctype Editable doctype object + */ + public function get($doctype) + { + if (isset($this->aliases[$doctype])) { + $doctype = $this->aliases[$doctype]; + } + if (!isset($this->doctypes[$doctype])) { + trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); + $anon = new HTMLPurifier_Doctype($doctype); + return $anon; + } + return $this->doctypes[$doctype]; + } + + /** + * Creates a doctype based on a configuration object, + * will perform initialization on the doctype + * @note Use this function to get a copy of doctype that config + * can hold on to (this is necessary in order to tell + * Generator whether or not the current document is XML + * based or not). + * @param HTMLPurifier_Config $config + * @return HTMLPurifier_Doctype + */ + public function make($config) + { + return clone $this->get($this->getDoctypeFromConfig($config)); + } + + /** + * Retrieves the doctype from the configuration object + * @param HTMLPurifier_Config $config + * @return string + */ + public function getDoctypeFromConfig($config) + { + // recommended test + $doctype = $config->get('HTML.Doctype'); + if (!empty($doctype)) { + return $doctype; + } + $doctype = $config->get('HTML.CustomDoctype'); + if (!empty($doctype)) { + return $doctype; + } + // backwards-compatibility + if ($config->get('HTML.XHTML')) { + $doctype = 'XHTML 1.0'; + } else { + $doctype = 'HTML 4.01'; + } + if ($config->get('HTML.Strict')) { + $doctype .= ' Strict'; + } else { + $doctype .= ' Transitional'; + } + return $doctype; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php new file mode 100644 index 0000000000..57cfd2bb08 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php @@ -0,0 +1,216 @@ +setup(), this array may also + * contain an array at index 0 that indicates which attribute + * collections to load into the full array. It may also + * contain string indentifiers in lieu of HTMLPurifier_AttrDef, + * see HTMLPurifier_AttrTypes on how they are expanded during + * HTMLPurifier_HTMLDefinition->setup() processing. + */ + public $attr = array(); + + // XXX: Design note: currently, it's not possible to override + // previously defined AttrTransforms without messing around with + // the final generated config. This is by design; a previous version + // used an associated list of attr_transform, but it was extremely + // easy to accidentally override other attribute transforms by + // forgetting to specify an index (and just using 0.) While we + // could check this by checking the index number and complaining, + // there is a second problem which is that it is not at all easy to + // tell when something is getting overridden. Combine this with a + // codebase where this isn't really being used, and it's perfect for + // nuking. + + /** + * List of tags HTMLPurifier_AttrTransform to be done before validation. + * @type array + */ + public $attr_transform_pre = array(); + + /** + * List of tags HTMLPurifier_AttrTransform to be done after validation. + * @type array + */ + public $attr_transform_post = array(); + + /** + * HTMLPurifier_ChildDef of this tag. + * @type HTMLPurifier_ChildDef + */ + public $child; + + /** + * Abstract string representation of internal ChildDef rules. + * @see HTMLPurifier_ContentSets for how this is parsed and then transformed + * into an HTMLPurifier_ChildDef. + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model; + + /** + * Value of $child->type, used to determine which ChildDef to use, + * used in combination with $content_model. + * @warning This must be lowercase + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model_type; + + /** + * Does the element have a content model (#PCDATA | Inline)*? This + * is important for chameleon ins and del processing in + * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't + * have to worry about this one. + * @type bool + */ + public $descendants_are_inline = false; + + /** + * List of the names of required attributes this element has. + * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement() + * @type array + */ + public $required_attr = array(); + + /** + * Lookup table of tags excluded from all descendants of this tag. + * @type array + * @note SGML permits exclusions for all descendants, but this is + * not possible with DTDs or XML Schemas. W3C has elected to + * use complicated compositions of content_models to simulate + * exclusion for children, but we go the simpler, SGML-style + * route of flat-out exclusions, which correctly apply to + * all descendants and not just children. Note that the XHTML + * Modularization Abstract Modules are blithely unaware of such + * distinctions. + */ + public $excludes = array(); + + /** + * This tag is explicitly auto-closed by the following tags. + * @type array + */ + public $autoclose = array(); + + /** + * If a foreign element is found in this element, test if it is + * allowed by this sub-element; if it is, instead of closing the + * current element, place it inside this element. + * @type string + */ + public $wrap; + + /** + * Whether or not this is a formatting element affected by the + * "Active Formatting Elements" algorithm. + * @type bool + */ + public $formatting; + + /** + * Low-level factory constructor for creating new standalone element defs + */ + public static function create($content_model, $content_model_type, $attr) + { + $def = new HTMLPurifier_ElementDef(); + $def->content_model = $content_model; + $def->content_model_type = $content_model_type; + $def->attr = $attr; + return $def; + } + + /** + * Merges the values of another element definition into this one. + * Values from the new element def take precedence if a value is + * not mergeable. + * @param HTMLPurifier_ElementDef $def + */ + public function mergeIn($def) + { + // later keys takes precedence + foreach ($def->attr as $k => $v) { + if ($k === 0) { + // merge in the includes + // sorry, no way to override an include + foreach ($v as $v2) { + $this->attr[0][] = $v2; + } + continue; + } + if ($v === false) { + if (isset($this->attr[$k])) { + unset($this->attr[$k]); + } + continue; + } + $this->attr[$k] = $v; + } + $this->_mergeAssocArray($this->excludes, $def->excludes); + $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre); + $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post); + + if (!empty($def->content_model)) { + $this->content_model = + str_replace("#SUPER", (string)$this->content_model, $def->content_model); + $this->child = false; + } + if (!empty($def->content_model_type)) { + $this->content_model_type = $def->content_model_type; + $this->child = false; + } + if (!is_null($def->child)) { + $this->child = $def->child; + } + if (!is_null($def->formatting)) { + $this->formatting = $def->formatting; + } + if ($def->descendants_are_inline) { + $this->descendants_are_inline = $def->descendants_are_inline; + } + } + + /** + * Merges one array into another, removes values which equal false + * @param $a1 Array by reference that is merged into + * @param $a2 Array that merges into $a1 + */ + private function _mergeAssocArray(&$a1, $a2) + { + foreach ($a2 as $k => $v) { + if ($v === false) { + if (isset($a1[$k])) { + unset($a1[$k]); + } + continue; + } + $a1[$k] = $v; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php new file mode 100644 index 0000000000..d4791cc1b6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php @@ -0,0 +1,617 @@ += $c) { + $r .= self::unsafeIconv($in, $out, substr($text, $i)); + break; + } + // wibble the boundary + if (0x80 != (0xC0 & ord($text[$i + $max_chunk_size]))) { + $chunk_size = $max_chunk_size; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 1]))) { + $chunk_size = $max_chunk_size - 1; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 2]))) { + $chunk_size = $max_chunk_size - 2; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 3]))) { + $chunk_size = $max_chunk_size - 3; + } else { + return false; // rather confusing UTF-8... + } + $chunk = substr($text, $i, $chunk_size); // substr doesn't mind overlong lengths + $r .= self::unsafeIconv($in, $out, $chunk); + $i += $chunk_size; + } + return $r; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Cleans a UTF-8 string for well-formedness and SGML validity + * + * It will parse according to UTF-8 and return a valid UTF8 string, with + * non-SGML codepoints excluded. + * + * Specifically, it will permit: + * \x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF} + * Source: https://www.w3.org/TR/REC-xml/#NT-Char + * Arguably this function should be modernized to the HTML5 set + * of allowed characters: + * https://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream + * which simultaneously expand and restrict the set of allowed characters. + * + * @param string $str The string to clean + * @param bool $force_php + * @return string + * + * @note Just for reference, the non-SGML code points are 0 to 31 and + * 127 to 159, inclusive. However, we allow code points 9, 10 + * and 13, which are the tab, line feed and carriage return + * respectively. 128 and above the code points map to multibyte + * UTF-8 representations. + * + * @note Fallback code adapted from utf8ToUnicode by Henri Sivonen and + * hsivonen@iki.fi at under the + * LGPL license. Notes on what changed are inside, but in general, + * the original code transformed UTF-8 text into an array of integer + * Unicode codepoints. Understandably, transforming that back to + * a string would be somewhat expensive, so the function was modded to + * directly operate on the string. However, this discourages code + * reuse, and the logic enumerated here would be useful for any + * function that needs to be able to understand UTF-8 characters. + * As of right now, only smart lossless character encoding converters + * would need that, and I'm probably not going to implement them. + */ + public static function cleanUTF8($str, $force_php = false) + { + // UTF-8 validity is checked since PHP 4.3.5 + // This is an optimization: if the string is already valid UTF-8, no + // need to do PHP stuff. 99% of the time, this will be the case. + if (preg_match( + '/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', + $str + )) { + return $str; + } + + $mState = 0; // cached expected number of octets after the current octet + // until the beginning of the next UTF8 character sequence + $mUcs4 = 0; // cached Unicode character + $mBytes = 1; // cached expected number of octets in the current sequence + + // original code involved an $out that was an array of Unicode + // codepoints. Instead of having to convert back into UTF-8, we've + // decided to directly append valid UTF-8 characters onto a string + // $out once they're done. $char accumulates raw bytes, while $mUcs4 + // turns into the Unicode code point, so there's some redundancy. + + $out = ''; + $char = ''; + + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $in = ord($str[$i]); + $char .= $str[$i]; // append byte to char + if (0 == $mState) { + // When mState is zero we expect either a US-ASCII character + // or a multi-octet sequence. + if (0 == (0x80 & ($in))) { + // US-ASCII, pass straight through. + if (($in <= 31 || $in == 127) && + !($in == 9 || $in == 13 || $in == 10) // save \r\t\n + ) { + // control characters, remove + } else { + $out .= $char; + } + // reset + $char = ''; + $mBytes = 1; + } elseif (0xC0 == (0xE0 & ($in))) { + // First octet of 2 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x1F) << 6; + $mState = 1; + $mBytes = 2; + } elseif (0xE0 == (0xF0 & ($in))) { + // First octet of 3 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x0F) << 12; + $mState = 2; + $mBytes = 3; + } elseif (0xF0 == (0xF8 & ($in))) { + // First octet of 4 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x07) << 18; + $mState = 3; + $mBytes = 4; + } elseif (0xF8 == (0xFC & ($in))) { + // First octet of 5 octet sequence. + // + // This is illegal because the encoded codepoint must be + // either: + // (a) not the shortest form or + // (b) outside the Unicode range of 0-0x10FFFF. + // Rather than trying to resynchronize, we will carry on + // until the end of the sequence and let the later error + // handling code catch it. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x03) << 24; + $mState = 4; + $mBytes = 5; + } elseif (0xFC == (0xFE & ($in))) { + // First octet of 6 octet sequence, see comments for 5 + // octet sequence. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 1) << 30; + $mState = 5; + $mBytes = 6; + } else { + // Current octet is neither in the US-ASCII range nor a + // legal first octet of a multi-octet sequence. + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // When mState is non-zero, we expect a continuation of the + // multi-octet sequence + if (0x80 == (0xC0 & ($in))) { + // Legal continuation. + $shift = ($mState - 1) * 6; + $tmp = $in; + $tmp = ($tmp & 0x0000003F) << $shift; + $mUcs4 |= $tmp; + + if (0 == --$mState) { + // End of the multi-octet sequence. mUcs4 now contains + // the final Unicode codepoint to be output + + // Check for illegal sequences and codepoints. + + // From Unicode 3.1, non-shortest form is illegal + if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || + ((3 == $mBytes) && ($mUcs4 < 0x0800)) || + ((4 == $mBytes) && ($mUcs4 < 0x10000)) || + (4 < $mBytes) || + // From Unicode 3.2, surrogate characters = illegal + (($mUcs4 & 0xFFFFF800) == 0xD800) || + // Codepoints outside the Unicode range are illegal + ($mUcs4 > 0x10FFFF) + ) { + + } elseif (0xFEFF != $mUcs4 && // omit BOM + // check for valid Char unicode codepoints + ( + 0x9 == $mUcs4 || + 0xA == $mUcs4 || + 0xD == $mUcs4 || + (0x20 <= $mUcs4 && 0x7E >= $mUcs4) || + // 7F-9F is not strictly prohibited by XML, + // but it is non-SGML, and thus we don't allow it + (0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) || + (0xE000 <= $mUcs4 && 0xFFFD >= $mUcs4) || + (0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4) + ) + ) { + $out .= $char; + } + // initialize UTF8 cache (reset) + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // ((0xC0 & (*in) != 0x80) && (mState != 0)) + // Incomplete multi-octet sequence. + // used to result in complete fail, but we'll reset + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char =''; + } + } + } + return $out; + } + + /** + * Translates a Unicode codepoint into its corresponding UTF-8 character. + * @note Based on Feyd's function at + * , + * which is in public domain. + * @note While we're going to do code point parsing anyway, a good + * optimization would be to refuse to translate code points that + * are non-SGML characters. However, this could lead to duplication. + * @note This is very similar to the unichr function in + * maintenance/generate-entity-file.php (although this is superior, + * due to its sanity checks). + */ + + // +----------+----------+----------+----------+ + // | 33222222 | 22221111 | 111111 | | + // | 10987654 | 32109876 | 54321098 | 76543210 | bit + // +----------+----------+----------+----------+ + // | | | | 0xxxxxxx | 1 byte 0x00000000..0x0000007F + // | | | 110yyyyy | 10xxxxxx | 2 byte 0x00000080..0x000007FF + // | | 1110zzzz | 10yyyyyy | 10xxxxxx | 3 byte 0x00000800..0x0000FFFF + // | 11110www | 10wwzzzz | 10yyyyyy | 10xxxxxx | 4 byte 0x00010000..0x0010FFFF + // +----------+----------+----------+----------+ + // | 00000000 | 00011111 | 11111111 | 11111111 | Theoretical upper limit of legal scalars: 2097151 (0x001FFFFF) + // | 00000000 | 00010000 | 11111111 | 11111111 | Defined upper limit of legal scalar codes + // +----------+----------+----------+----------+ + + public static function unichr($code) + { + if ($code > 1114111 or $code < 0 or + ($code >= 55296 and $code <= 57343) ) { + // bits are set outside the "valid" range as defined + // by UNICODE 4.1.0 + return ''; + } + + $x = $y = $z = $w = 0; + if ($code < 128) { + // regular ASCII character + $x = $code; + } else { + // set up bits for UTF-8 + $x = ($code & 63) | 128; + if ($code < 2048) { + $y = (($code & 2047) >> 6) | 192; + } else { + $y = (($code & 4032) >> 6) | 128; + if ($code < 65536) { + $z = (($code >> 12) & 15) | 224; + } else { + $z = (($code >> 12) & 63) | 128; + $w = (($code >> 18) & 7) | 240; + } + } + } + // set up the actual character + $ret = ''; + if ($w) { + $ret .= chr($w); + } + if ($z) { + $ret .= chr($z); + } + if ($y) { + $ret .= chr($y); + } + $ret .= chr($x); + + return $ret; + } + + /** + * @return bool + */ + public static function iconvAvailable() + { + static $iconv = null; + if ($iconv === null) { + $iconv = function_exists('iconv') && self::testIconvTruncateBug() != self::ICONV_UNUSABLE; + } + return $iconv; + } + + /** + * Convert a string to UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public static function convertToUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // unaffected by bugs, since UTF-8 support all characters + $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str); + if ($str === false) { + // $encoding is not a valid encoding + trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); + return ''; + } + // If the string is bjorked by Shift_JIS or a similar encoding + // that doesn't support all of ASCII, convert the naughty + // characters to their true byte-wise ASCII/UTF-8 equivalents. + $str = strtr($str, self::testEncodingSupportsASCII($encoding)); + return $str; + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1'); + return $str; + } + $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); + if ($bug == self::ICONV_OK) { + trigger_error('Encoding not supported, please install iconv', E_USER_ERROR); + } else { + trigger_error( + 'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' . + 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541', + E_USER_ERROR + ); + } + } + + /** + * Converts a string from UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + * @note Currently, this is a lossy conversion, with unexpressable + * characters being omitted. + */ + public static function convertFromUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($escape = $config->get('Core.EscapeNonASCIICharacters')) { + $str = self::convertToASCIIDumbLossless($str); + } + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // Undo our previous fix in convertToUTF8, otherwise iconv will barf + $ascii_fix = self::testEncodingSupportsASCII($encoding); + if (!$escape && !empty($ascii_fix)) { + $clear_fix = array(); + foreach ($ascii_fix as $utf8 => $native) { + $clear_fix[$utf8] = ''; + } + $str = strtr($str, $clear_fix); + } + $str = strtr($str, array_flip($ascii_fix)); + // Normal stuff + $str = self::iconv('utf-8', $encoding . '//IGNORE', $str); + return $str; + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); + return $str; + } + trigger_error('Encoding not supported', E_USER_ERROR); + // You might be tempted to assume that the ASCII representation + // might be OK, however, this is *not* universally true over all + // encodings. So we take the conservative route here, rather + // than forcibly turn on %Core.EscapeNonASCIICharacters + } + + /** + * Lossless (character-wise) conversion of HTML to ASCII + * @param string $str UTF-8 string to be converted to ASCII + * @return string ASCII encoded string with non-ASCII character entity-ized + * @warning Adapted from MediaWiki, claiming fair use: this is a common + * algorithm. If you disagree with this license fudgery, + * implement it yourself. + * @note Uses decimal numeric entities since they are best supported. + * @note This is a DUMB function: it has no concept of keeping + * character entities that the projected character encoding + * can allow. We could possibly implement a smart version + * but that would require it to also know which Unicode + * codepoints the charset supported (not an easy task). + * @note Sort of with cleanUTF8() but it assumes that $str is + * well-formed UTF-8 + */ + public static function convertToASCIIDumbLossless($str) + { + $bytesleft = 0; + $result = ''; + $working = 0; + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $bytevalue = ord($str[$i]); + if ($bytevalue <= 0x7F) { //0xxx xxxx + $result .= chr($bytevalue); + $bytesleft = 0; + } elseif ($bytevalue <= 0xBF) { //10xx xxxx + $working = $working << 6; + $working += ($bytevalue & 0x3F); + $bytesleft--; + if ($bytesleft <= 0) { + $result .= "&#" . $working . ";"; + } + } elseif ($bytevalue <= 0xDF) { //110x xxxx + $working = $bytevalue & 0x1F; + $bytesleft = 1; + } elseif ($bytevalue <= 0xEF) { //1110 xxxx + $working = $bytevalue & 0x0F; + $bytesleft = 2; + } else { //1111 0xxx + $working = $bytevalue & 0x07; + $bytesleft = 3; + } + } + return $result; + } + + /** No bugs detected in iconv. */ + const ICONV_OK = 0; + + /** Iconv truncates output if converting from UTF-8 to another + * character set with //IGNORE, and a non-encodable character is found */ + const ICONV_TRUNCATES = 1; + + /** Iconv does not support //IGNORE, making it unusable for + * transcoding purposes */ + const ICONV_UNUSABLE = 2; + + /** + * glibc iconv has a known bug where it doesn't handle the magic + * //IGNORE stanza correctly. In particular, rather than ignore + * characters, it will return an EILSEQ after consuming some number + * of characters, and expect you to restart iconv as if it were + * an E2BIG. Old versions of PHP did not respect the errno, and + * returned the fragment, so as a result you would see iconv + * mysteriously truncating output. We can work around this by + * manually chopping our input into segments of about 8000 + * characters, as long as PHP ignores the error code. If PHP starts + * paying attention to the error code, iconv becomes unusable. + * + * @return int Error code indicating severity of bug. + */ + public static function testIconvTruncateBug() + { + static $code = null; + if ($code === null) { + // better not use iconv, otherwise infinite loop! + $r = self::unsafeIconv('utf-8', 'ascii//IGNORE', "\xCE\xB1" . str_repeat('a', 9000)); + if ($r === false) { + $code = self::ICONV_UNUSABLE; + } elseif (($c = strlen($r)) < 9000) { + $code = self::ICONV_TRUNCATES; + } elseif ($c > 9000) { + trigger_error( + 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' . + 'include your iconv version as per phpversion()', + E_USER_ERROR + ); + } else { + $code = self::ICONV_OK; + } + } + return $code; + } + + /** + * This expensive function tests whether or not a given character + * encoding supports ASCII. 7/8-bit encodings like Shift_JIS will + * fail this test, and require special processing. Variable width + * encodings shouldn't ever fail. + * + * @param string $encoding Encoding name to test, as per iconv format + * @param bool $bypass Whether or not to bypass the precompiled arrays. + * @return Array of UTF-8 characters to their corresponding ASCII, + * which can be used to "undo" any overzealous iconv action. + */ + public static function testEncodingSupportsASCII($encoding, $bypass = false) + { + // All calls to iconv here are unsafe, proof by case analysis: + // If ICONV_OK, no difference. + // If ICONV_TRUNCATE, all calls involve one character inputs, + // so bug is not triggered. + // If ICONV_UNUSABLE, this call is irrelevant + static $encodings = array(); + if (!$bypass) { + if (isset($encodings[$encoding])) { + return $encodings[$encoding]; + } + $lenc = strtolower($encoding); + switch ($lenc) { + case 'shift_jis': + return array("\xC2\xA5" => '\\', "\xE2\x80\xBE" => '~'); + case 'johab': + return array("\xE2\x82\xA9" => '\\'); + } + if (strpos($lenc, 'iso-8859-') === 0) { + return array(); + } + } + $ret = array(); + if (self::unsafeIconv('UTF-8', $encoding, 'a') === false) { + return false; + } + for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars + $c = chr($i); // UTF-8 char + $r = self::unsafeIconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion + if ($r === '' || + // This line is needed for iconv implementations that do not + // omit characters that do not exist in the target character set + ($r === $c && self::unsafeIconv($encoding, 'UTF-8//IGNORE', $r) !== $c) + ) { + // Reverse engineer: what's the UTF-8 equiv of this byte + // sequence? This assumes that there's no variable width + // encoding that doesn't support ASCII. + $ret[self::unsafeIconv($encoding, 'UTF-8//IGNORE', $c)] = $c; + } + } + $encodings[$encoding] = $ret; + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php new file mode 100644 index 0000000000..f12ff13a35 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php @@ -0,0 +1,48 @@ +table = unserialize(file_get_contents($file)); + } + + /** + * Retrieves sole instance of the object. + * @param bool|HTMLPurifier_EntityLookup $prototype Optional prototype of custom lookup table to overload with. + * @return HTMLPurifier_EntityLookup + */ + public static function instance($prototype = false) + { + // no references, since PHP doesn't copy unless modified + static $instance = null; + if ($prototype) { + $instance = $prototype; + } elseif (!$instance) { + $instance = new HTMLPurifier_EntityLookup(); + $instance->setup(); + } + return $instance; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser new file mode 100644 index 0000000000..e8b08128be --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser @@ -0,0 +1 @@ +a:253:{s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:6:"there4";s:3:"∴";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:4:"sup2";s:2:"²";s:4:"sup3";s:2:"³";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"sup1";s:2:"¹";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"frac14";s:2:"¼";s:6:"frac12";s:2:"½";s:6:"frac34";s:2:"¾";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";} \ No newline at end of file diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php new file mode 100644 index 0000000000..0f2b83dc8d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php @@ -0,0 +1,285 @@ +_semiOptionalPrefixRegex = "/&()()()($semi_optional)/"; + + $this->_textEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + "($semi_optional)". + ')/'; + + $this->_attrEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + // don't match if trailing is equals or alphanumeric (URL + // like) + "($semi_optional)(?![=;A-Za-z0-9])". + ')/'; + + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * textual data in an HTML document (as opposed to attributes.) + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteTextEntities($string) + { + return preg_replace_callback( + $this->_textEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * attribute contents in documents. + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteAttrEntities($string) + { + return preg_replace_callback( + $this->_attrEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function entityCallback($matches) + { + $entity = $matches[0]; + $hex_part = isset($matches[1]) ? $matches[1] : null; + $dec_part = isset($matches[2]) ? $matches[2] : null; + $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3]; + if ($hex_part !== NULL && $hex_part !== "") { + return HTMLPurifier_Encoder::unichr(hexdec($hex_part)); + } elseif ($dec_part !== NULL && $dec_part !== "") { + return HTMLPurifier_Encoder::unichr((int) $dec_part); + } else { + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$named_part])) { + return $this->_entity_lookup->table[$named_part]; + } else { + // exact match didn't match anything, so test if + // any of the semicolon optional match the prefix. + // Test that this is an EXACT match is important to + // prevent infinite loop + if (!empty($matches[3])) { + return preg_replace_callback( + $this->_semiOptionalPrefixRegex, + array($this, 'entityCallback'), + $entity + ); + } + return $entity; + } + } + } + + // LEGACY CODE BELOW + + /** + * Callback regex string for parsing entities. + * @type string + */ + protected $_substituteEntitiesRegex = + '/&(?:[#]x([a-fA-F0-9]+)|[#]0*(\d+)|([A-Za-z_:][A-Za-z0-9.\-_:]*));?/'; + // 1. hex 2. dec 3. string (XML style) + + /** + * Decimal to parsed string conversion table for special entities. + * @type array + */ + protected $_special_dec2str = + array( + 34 => '"', + 38 => '&', + 39 => "'", + 60 => '<', + 62 => '>' + ); + + /** + * Stripped entity names to decimal conversion table for special entities. + * @type array + */ + protected $_special_ent2dec = + array( + 'quot' => 34, + 'amp' => 38, + 'lt' => 60, + 'gt' => 62 + ); + + /** + * Substitutes non-special entities with their parsed equivalents. Since + * running this whenever you have parsed character is t3h 5uck, we run + * it before everything else. + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteNonSpecialEntities($string) + { + // it will try to detect missing semicolons, but don't rely on it + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'nonSpecialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function nonSpecialEntityCallback($matches) + { + // replaces all but big five + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $code = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + // abort for special characters + if (isset($this->_special_dec2str[$code])) { + return $entity; + } + return HTMLPurifier_Encoder::unichr($code); + } else { + if (isset($this->_special_ent2dec[$matches[3]])) { + return $entity; + } + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$matches[3]])) { + return $this->_entity_lookup->table[$matches[3]]; + } else { + return $entity; + } + } + } + + /** + * Substitutes only special entities with their parsed equivalents. + * + * @notice We try to avoid calling this function because otherwise, it + * would have to be called a lot (for every parsed section). + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteSpecialEntities($string) + { + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'specialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteSpecialEntities() that does the work. + * + * This callback has same syntax as nonSpecialEntityCallback(). + * + * @param array $matches PCRE-style matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + protected function specialEntityCallback($matches) + { + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $int = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + return isset($this->_special_dec2str[$int]) ? + $this->_special_dec2str[$int] : + $entity; + } else { + return isset($this->_special_ent2dec[$matches[3]]) ? + $this->_special_dec2str[$this->_special_ent2dec[$matches[3]]] : + $entity; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php new file mode 100644 index 0000000000..d47e3f2e24 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php @@ -0,0 +1,244 @@ +locale =& $context->get('Locale'); + $this->context = $context; + $this->_current =& $this->_stacks[0]; + $this->errors =& $this->_stacks[0]; + } + + /** + * Sends an error message to the collector for later use + * @param int $severity Error severity, PHP error style (don't use E_USER_) + * @param string $msg Error message text + */ + public function send($severity, $msg) + { + $args = array(); + if (func_num_args() > 2) { + $args = func_get_args(); + array_shift($args); + unset($args[0]); + } + + $token = $this->context->get('CurrentToken', true); + $line = $token ? $token->line : $this->context->get('CurrentLine', true); + $col = $token ? $token->col : $this->context->get('CurrentCol', true); + $attr = $this->context->get('CurrentAttr', true); + + // perform special substitutions, also add custom parameters + $subst = array(); + if (!is_null($token)) { + $args['CurrentToken'] = $token; + } + if (!is_null($attr)) { + $subst['$CurrentAttr.Name'] = $attr; + if (isset($token->attr[$attr])) { + $subst['$CurrentAttr.Value'] = $token->attr[$attr]; + } + } + + if (empty($args)) { + $msg = $this->locale->getMessage($msg); + } else { + $msg = $this->locale->formatMessage($msg, $args); + } + + if (!empty($subst)) { + $msg = strtr($msg, $subst); + } + + // (numerically indexed) + $error = array( + self::LINENO => $line, + self::SEVERITY => $severity, + self::MESSAGE => $msg, + self::CHILDREN => array() + ); + $this->_current[] = $error; + + // NEW CODE BELOW ... + // Top-level errors are either: + // TOKEN type, if $value is set appropriately, or + // "syntax" type, if $value is null + $new_struct = new HTMLPurifier_ErrorStruct(); + $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN; + if ($token) { + $new_struct->value = clone $token; + } + if (is_int($line) && is_int($col)) { + if (isset($this->lines[$line][$col])) { + $struct = $this->lines[$line][$col]; + } else { + $struct = $this->lines[$line][$col] = $new_struct; + } + // These ksorts may present a performance problem + ksort($this->lines[$line], SORT_NUMERIC); + } else { + if (isset($this->lines[-1])) { + $struct = $this->lines[-1]; + } else { + $struct = $this->lines[-1] = $new_struct; + } + } + ksort($this->lines, SORT_NUMERIC); + + // Now, check if we need to operate on a lower structure + if (!empty($attr)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr); + if (!$struct->value) { + $struct->value = array($attr, 'PUT VALUE HERE'); + } + } + if (!empty($cssprop)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop); + if (!$struct->value) { + // if we tokenize CSS this might be a little more difficult to do + $struct->value = array($cssprop, 'PUT VALUE HERE'); + } + } + + // Ok, structs are all setup, now time to register the error + $struct->addError($severity, $msg); + } + + /** + * Retrieves raw error data for custom formatter to use + */ + public function getRaw() + { + return $this->errors; + } + + /** + * Default HTML formatting implementation for error messages + * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature + * @param array $errors Errors array to display; used for recursion. + * @return string + */ + public function getHTMLFormatted($config, $errors = null) + { + $ret = array(); + + $this->generator = new HTMLPurifier_Generator($config, $this->context); + if ($errors === null) { + $errors = $this->errors; + } + + // 'At line' message needs to be removed + + // generation code for new structure goes here. It needs to be recursive. + foreach ($this->lines as $line => $col_array) { + if ($line == -1) { + continue; + } + foreach ($col_array as $col => $struct) { + $this->_renderStruct($ret, $struct, $line, $col); + } + } + if (isset($this->lines[-1])) { + $this->_renderStruct($ret, $this->lines[-1]); + } + + if (empty($errors)) { + return '

' . $this->locale->getMessage('ErrorCollector: No errors') . '

'; + } else { + return '
  • ' . implode('
  • ', $ret) . '
'; + } + + } + + private function _renderStruct(&$ret, $struct, $line = null, $col = null) + { + $stack = array($struct); + $context_stack = array(array()); + while ($current = array_pop($stack)) { + $context = array_pop($context_stack); + foreach ($current->errors as $error) { + list($severity, $msg) = $error; + $string = ''; + $string .= '
'; + // W3C uses an icon to indicate the severity of the error. + $error = $this->locale->getErrorName($severity); + $string .= "$error "; + if (!is_null($line) && !is_null($col)) { + $string .= "Line $line, Column $col: "; + } else { + $string .= 'End of Document: '; + } + $string .= '' . $this->generator->escape($msg) . ' '; + $string .= '
'; + // Here, have a marker for the character on the column appropriate. + // Be sure to clip extremely long lines. + //$string .= '
';
+                //$string .= '';
+                //$string .= '
'; + $ret[] = $string; + } + foreach ($current->children as $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php new file mode 100644 index 0000000000..cf869d3212 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,74 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + /** + * @param int $severity + * @param string $message + */ + public function addError($severity, $message) + { + $this->errors[] = array($severity, $message); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php new file mode 100644 index 0000000000..be85b4c560 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, + * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, + * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step + */ + +class HTMLPurifier_Filter +{ + + /** + * Name of the filter for identification purposes. + * @type string + */ + public $name; + + /** + * Pre-processor function, handles HTML before HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function preFilter($html, $config, $context) + { + return $html; + } + + /** + * Post-processor function, handles HTML after HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100644 index 0000000000..e7e3cac1ad --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,362 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + /** + * @type string + */ + public $name = 'ExtractStyleBlocks'; + + /** + * @type array + */ + private $_styleMatches = array(); + + /** + * @type csstidy + */ + private $_tidy; + + /** + * @type HTMLPurifier_AttrDef_HTML_ID + */ + private $_id_attrdef; + + /** + * @type HTMLPurifier_AttrDef_CSS_Ident + */ + private $_class_attrdef; + + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_enum_attrdef; + + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_universal_attrdef; + + public function __construct() + { + $this->_tidy = new csstidy(); + $this->_tidy->set_cfg('lowercase_s', false); + $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true); + $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident(); + $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'first-child', + 'link', + 'visited', + 'active', + 'hover', + 'focus' + ) + ); + $this->_universal_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'initial', + 'inherit', + 'unset', + ) + ); + } + + /** + * Save the contents of CSS blocks to style matches + * @param array $matches preg_replace style $matches array + */ + protected function styleCallback($matches) + { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline + // we must not grab foo in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 0000000000..276d8362fa --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + '(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return '' . + '' . + '' . + ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php new file mode 100644 index 0000000000..eb56e2dfa2 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php @@ -0,0 +1,286 @@ + tags. + * @type bool + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + * @type HTMLPurifier_HTMLDefinition + */ + private $_def; + + /** + * Cache of %Output.SortAttr. + * @type bool + */ + private $_sortAttr; + + /** + * Cache of %Output.FlashCompat. + * @type bool + */ + private $_flashCompat; + + /** + * Cache of %Output.FixInnerHTML. + * @type bool + */ + private $_innerHTMLFix; + + /** + * Stack for keeping track of object information when outputting IE + * compatibility code. + * @type array + */ + private $_flashStack = array(); + + /** + * Configuration for the generator + * @type HTMLPurifier_Config + */ + protected $config; + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + public function __construct($config, $context) + { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_innerHTMLFix = $config->get('Output.FixInnerHTML'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_flashCompat = $config->get('Output.FlashCompat'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token + * @return string Generated HTML + */ + public function generateFromTokens($tokens) + { + if (!$tokens) { + return ''; + } + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString( + $html, + array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), + 'utf8' + ); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + if ($this->config->get('Core.NormalizeNewlines')) { + $nl = $this->config->get('Output.Newline'); + if ($nl === null) { + $nl = PHP_EOL; + } + if ($nl !== "\n") { + $html = str_replace("\n", $nl, $html); + } + } + return $html; + } + + /** + * Generates HTML from a single token. + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string Generated HTML + */ + public function generateFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + if ($this->_flashCompat) { + if ($token->name == "object") { + $flash = new stdClass(); + $flash->attr = $token->attr; + $flash->param = array(); + $this->_flashStack[] = $flash; + } + } + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + $_extra = ''; + if ($this->_flashCompat) { + if ($token->name == "object" && !empty($this->_flashStack)) { + // doesn't do anything for now + } + } + return $_extra . 'name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + if ($this->_flashCompat && $token->name == "param" && !empty($this->_flashStack)) { + $this->_flashStack[count($this->_flashStack)-1]->param[$token->attr['name']] = $token->attr['value']; + } + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
v.
+ . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Text) { + return $this->escape($token->data, ENT_NOQUOTES); + + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + return ''; + } else { + return ''; + + } + } + + /** + * Special case processor for the contents of script tags + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string + * @warning This runs into problems if there's already a literal + * --> somewhere inside the script contents. + */ + public function generateScriptFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token_Text) { + return $this->generateFromToken($token); + } + // Thanks + $data = preg_replace('#//\s*$#', '', $token->data); + return ''; + } + + /** + * Generates attribute declarations from attribute array. + * @note This does not include the leading or trailing space. + * @param array $assoc_array_of_attributes Attribute array + * @param string $element Name of element attributes are for, used to check + * attribute minimization. + * @return string Generated HTML fragment for insertion. + */ + public function generateAttributes($assoc_array_of_attributes, $element = '') + { + $html = ''; + if ($this->_sortAttr) { + ksort($assoc_array_of_attributes); + } + foreach ($assoc_array_of_attributes as $key => $value) { + if (!$this->_xhtml) { + // Remove namespaced attributes + if (strpos($key, ':') !== false) { + continue; + } + // Check if we should minimize the attribute: val="val" -> val + if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) { + $html .= $key . ' '; + continue; + } + } + // Workaround for Internet Explorer innerHTML bug. + // Essentially, Internet Explorer, when calculating + // innerHTML, omits quotes if there are no instances of + // angled brackets, quotes or spaces. However, when parsing + // HTML (for example, when you assign to innerHTML), it + // treats backticks as quotes. Thus, + // `` + // becomes + // `` + // becomes + // + // Fortunately, all we need to do is trigger an appropriate + // quoting style, which we do by adding an extra space. + // This also is consistent with the W3C spec, which states + // that user agents may ignore leading or trailing + // whitespace (in fact, most don't, at least for attributes + // like alt, but an extra space at the end is barely + // noticeable). Still, we have a configuration knob for + // this, since this transformation is not necesary if you + // don't process user input with innerHTML or you don't plan + // on supporting Internet Explorer. + if ($this->_innerHTMLFix) { + if (strpos($value, '`') !== false) { + // check if correct quoting style would not already be + // triggered + if (strcspn($value, '"\' <>') === strlen($value)) { + // protect! + $value .= ' '; + } + } + } + $html .= $key.'="'.$this->escape($value).'" '; + } + return rtrim($html); + } + + /** + * Escapes raw text data. + * @todo This really ought to be protected, but until we have a facility + * for properly generating HTML here w/o using tokens, it stays + * public. + * @param string $string String data to escape for HTML. + * @param int $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is + * permissible for non-attribute output. + * @return string escaped data. + */ + public function escape($string, $quote = null) + { + // Workaround for APC bug on Mac Leopard reported by sidepodcast + // http://htmlpurifier.org/phorum/read.php?3,4823,4846 + if ($quote === null) { + $quote = ENT_COMPAT; + } + return htmlspecialchars($string, $quote, 'UTF-8'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php new file mode 100644 index 0000000000..9b7b334dd9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php @@ -0,0 +1,493 @@ +getAnonymousModule(); + if (!isset($module->info[$element_name])) { + $element = $module->addBlankElement($element_name); + } else { + $element = $module->info[$element_name]; + } + $element->attr[$attr_name] = $def; + } + + /** + * Adds a custom element to your HTML definition + * @see HTMLPurifier_HTMLModule::addElement() for detailed + * parameter and return value descriptions. + */ + public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) + { + $module = $this->getAnonymousModule(); + // assume that if the user is calling this, the element + // is safe. This may not be a good idea + $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @param string $element_name + * @return HTMLPurifier_ElementDef + * @see HTMLPurifier_HTMLModule::addBlankElement() for detailed + * parameter and return value descriptions. + */ + public function addBlankElement($element_name) + { + $module = $this->getAnonymousModule(); + $element = $module->addBlankElement($element_name); + return $element; + } + + /** + * Retrieves a reference to the anonymous module, so you can + * bust out advanced features without having to make your own + * module. + * @return HTMLPurifier_HTMLModule + */ + public function getAnonymousModule() + { + if (!$this->_anonModule) { + $this->_anonModule = new HTMLPurifier_HTMLModule(); + $this->_anonModule->name = 'Anonymous'; + } + return $this->_anonModule; + } + + private $_anonModule = null; + + // PUBLIC BUT INTERNAL VARIABLES -------------------------------------- + + /** + * @type string + */ + public $type = 'HTML'; + + /** + * @type HTMLPurifier_HTMLModuleManager + */ + public $manager; + + /** + * Performs low-cost, preliminary initialization. + */ + public function __construct() + { + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetup($config) + { + $this->processModules($config); + $this->setupConfigStuff($config); + unset($this->manager); + + // cleanup some of the element definitions + foreach ($this->info as $k => $v) { + unset($this->info[$k]->content_model); + unset($this->info[$k]->content_model_type); + } + } + + /** + * Extract out the information from the manager + * @param HTMLPurifier_Config $config + */ + protected function processModules($config) + { + if ($this->_anonModule) { + // for user specific changes + // this is late-loaded so we don't have to deal with PHP4 + // reference wonky-ness + $this->manager->addModule($this->_anonModule); + unset($this->_anonModule); + } + + $this->manager->setup($config); + $this->doctype = $this->manager->doctype; + + foreach ($this->manager->modules as $module) { + foreach ($module->info_tag_transform as $k => $v) { + if ($v === false) { + unset($this->info_tag_transform[$k]); + } else { + $this->info_tag_transform[$k] = $v; + } + } + foreach ($module->info_attr_transform_pre as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_pre[$k]); + } else { + $this->info_attr_transform_pre[$k] = $v; + } + } + foreach ($module->info_attr_transform_post as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_post[$k]); + } else { + $this->info_attr_transform_post[$k] = $v; + } + } + foreach ($module->info_injector as $k => $v) { + if ($v === false) { + unset($this->info_injector[$k]); + } else { + $this->info_injector[$k] = $v; + } + } + } + $this->info = $this->manager->getElements(); + $this->info_content_sets = $this->manager->contentSets->lookup; + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + * @param HTMLPurifier_Config $config + */ + protected function setupConfigStuff($config) + { + $block_wrapper = $config->get('HTML.BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error( + 'Cannot use non-block element as block wrapper', + E_USER_ERROR + ); + } + + $parent = $config->get('HTML.Parent'); + $def = $this->manager->getElement($parent, true); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error( + 'Cannot use unrecognized element as parent', + E_USER_ERROR + ); + $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + } + + // support template text + $support = "(for information on implementing this, see the support forums) "; + + // setup allowed elements ----------------------------------------- + + $allowed_elements = $config->get('HTML.AllowedElements'); + $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early + + if (!is_array($allowed_elements) && !is_array($allowed_attributes)) { + $allowed = $config->get('HTML.Allowed'); + if (is_string($allowed)) { + list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed); + } + } + + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_elements[$name])) { + unset($this->info[$name]); + } + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful! + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + // setup allowed attributes --------------------------------------- + + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + // This actually doesn't do anything, since we went away from + // global attributes. It's possible that userland code uses + // it, but HTMLModuleManager doesn't! + foreach ($this->info_global_attr as $attr => $x) { + $keys = array($attr, "*@$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + unset($this->info_global_attr[$attr]); + } + } + + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $x) { + $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + if ($this->info[$tag]->attr[$attr]->required) { + trigger_error( + "Required attribute '$attr' in element '$tag' " . + "was not allowed, which means '$tag' will not be allowed either", + E_USER_WARNING + ); + } + unset($this->info[$tag]->attr[$attr]); + } + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + $bits = preg_split('/[.@]/', $elattr, 2); + $c = count($bits); + switch ($c) { + case 2: + if ($bits[0] !== '*') { + $element = htmlspecialchars($bits[0]); + $attribute = htmlspecialchars($bits[1]); + if (!isset($this->info[$element])) { + trigger_error( + "Cannot allow attribute '$attribute' if element " . + "'$element' is not allowed/supported $support" + ); + } else { + trigger_error( + "Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING + ); + } + break; + } + // otherwise fall through + case 1: + $attribute = htmlspecialchars($bits[0]); + trigger_error( + "Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING + ); + break; + } + } + } + + // setup forbidden elements --------------------------------------- + + $forbidden_elements = $config->get('HTML.ForbiddenElements'); + $forbidden_attributes = $config->get('HTML.ForbiddenAttributes'); + + foreach ($this->info as $tag => $info) { + if (isset($forbidden_elements[$tag])) { + unset($this->info[$tag]); + continue; + } + foreach ($info->attr as $attr => $x) { + if (isset($forbidden_attributes["$tag@$attr"]) || + isset($forbidden_attributes["*@$attr"]) || + isset($forbidden_attributes[$attr]) + ) { + unset($this->info[$tag]->attr[$attr]); + continue; + } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually + // $tag.$attr are not user supplied, so no worries! + trigger_error( + "Error with $tag.$attr: tag.attr syntax not supported for " . + "HTML.ForbiddenAttributes; use tag@attr instead", + E_USER_WARNING + ); + } + } + } + foreach ($forbidden_attributes as $key => $v) { + if (strlen($key) < 2) { + continue; + } + if ($key[0] != '*') { + continue; + } + if ($key[1] == '.') { + trigger_error( + "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", + E_USER_WARNING + ); + } + } + + // setup injectors ----------------------------------------------------- + foreach ($this->info_injector as $i => $injector) { + if ($injector->checkNeeded($config) !== false) { + // remove injector that does not have it's required + // elements/attributes present, and is thus not needed. + unset($this->info_injector[$i]); + } + } + } + + /** + * Parses a TinyMCE-flavored Allowed Elements and Attributes list into + * separate lists for processing. Format is element[attr1|attr2],element2... + * @warning Although it's largely drawn from TinyMCE's implementation, + * it is different, and you'll probably have to modify your lists + * @param array $list String list to parse + * @return array + * @todo Give this its own class, probably static interface + */ + public function parseTinyMCEAllowedList($list) + { + $list = str_replace(array(' ', "\t"), '', $list); + + $elements = array(); + $attributes = array(); + + $chunks = preg_split('/(,|[\n\r]+)/', $list); + foreach ($chunks as $chunk) { + if (empty($chunk)) { + continue; + } + // remove TinyMCE element control characters + if (!strpos($chunk, '[')) { + $element = $chunk; + $attr = false; + } else { + list($element, $attr) = explode('[', $chunk); + } + if ($element !== '*') { + $elements[$element] = true; + } + if (!$attr) { + continue; + } + $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ] + $attr = explode('|', $attr); + foreach ($attr as $key) { + $attributes["$element.$key"] = true; + } + } + return array($elements, $attributes); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php new file mode 100644 index 0000000000..9dbb987290 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php @@ -0,0 +1,285 @@ +info, since the object's data is only info, + * with extra behavior associated with it. + * @type array + */ + public $attr_collections = array(); + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform. + * @type array + */ + public $info_tag_transform = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed before validation. + * @type array + */ + public $info_attr_transform_pre = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed after validation. + * @type array + */ + public $info_attr_transform_post = array(); + + /** + * List of HTMLPurifier_Injector to be performed during well-formedness fixing. + * An injector will only be invoked if all of it's pre-requisites are met; + * if an injector fails setup, there will be no error; it will simply be + * silently disabled. + * @type array + */ + public $info_injector = array(); + + /** + * Boolean flag that indicates whether or not getChildDef is implemented. + * For optimization reasons: may save a call to a function. Be sure + * to set it if you do implement getChildDef(), otherwise it will have + * no effect! + * @type bool + */ + public $defines_child_def = false; + + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @type bool + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + + /** + * Retrieves a proper HTMLPurifier_ChildDef subclass based on + * content_model and content_model_type member variables of + * the HTMLPurifier_ElementDef class. There is a similar function + * in HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef subclass + */ + public function getChildDef($def) + { + return false; + } + + // -- Convenience ----------------------------------------------------- + + /** + * Convenience function that sets up a new element + * @param string $element Name of element to add + * @param string|bool $type What content set should element be registered to? + * Set as false to skip this step. + * @param string|HTMLPurifier_ChildDef $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @param array|string $attr_includes What attribute collections to register to + * element? + * @param array $attr What unique attributes does the element define? + * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters. + * @return HTMLPurifier_ElementDef Created element definition object, so you + * can set advanced parameters + */ + public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) + { + $this->elements[] = $element; + // parse content_model + list($content_model_type, $content_model) = $this->parseContents($contents); + // merge in attribute inclusions + $this->mergeInAttrIncludes($attr, $attr_includes); + // add element to content sets + if ($type) { + $this->addElementToContentSet($element, $type); + } + // create element + $this->info[$element] = HTMLPurifier_ElementDef::create( + $content_model, + $content_model_type, + $attr + ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) { + $this->info[$element]->child = $contents; + } + return $this->info[$element]; + } + + /** + * Convenience function that creates a totally blank, non-standalone + * element. + * @param string $element Name of element to create + * @return HTMLPurifier_ElementDef Created element + */ + public function addBlankElement($element) + { + if (!isset($this->info[$element])) { + $this->elements[] = $element; + $this->info[$element] = new HTMLPurifier_ElementDef(); + $this->info[$element]->standalone = false; + } else { + trigger_error("Definition for $element already exists in module, cannot redefine"); + } + return $this->info[$element]; + } + + /** + * Convenience function that registers an element to a content set + * @param string $element Element to register + * @param string $type Name content set (warning: case sensitive, usually upper-case + * first letter) + */ + public function addElementToContentSet($element, $type) + { + if (!isset($this->content_sets[$type])) { + $this->content_sets[$type] = ''; + } else { + $this->content_sets[$type] .= ' | '; + } + $this->content_sets[$type] .= $element; + } + + /** + * Convenience function that transforms single-string contents + * into separate content model and content model type + * @param string $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @return array + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. + */ + public function parseContents($contents) + { + if (!is_string($contents)) { + return array(null, null); + } // defer + switch ($contents) { + // check for shorthand content model forms + case 'Empty': + return array('empty', ''); + case 'Inline': + return array('optional', 'Inline | #PCDATA'); + case 'Flow': + return array('optional', 'Flow | #PCDATA'); + } + list($content_model_type, $content_model) = explode(':', $contents); + $content_model_type = strtolower(trim($content_model_type)); + $content_model = trim($content_model); + return array($content_model_type, $content_model); + } + + /** + * Convenience function that merges a list of attribute includes into + * an attribute array. + * @param array $attr Reference to attr array to modify + * @param array $attr_includes Array of includes / string include to merge in + */ + public function mergeInAttrIncludes(&$attr, $attr_includes) + { + if (!is_array($attr_includes)) { + if (empty($attr_includes)) { + $attr_includes = array(); + } else { + $attr_includes = array($attr_includes); + } + } + $attr[0] = $attr_includes; + } + + /** + * Convenience function that generates a lookup table with boolean + * true as value. + * @param string $list List of values to turn into a lookup + * @note You can also pass an arbitrary number of arguments in + * place of the regular argument + * @return array array equivalent of list + */ + public function makeLookup($list) + { + $args = func_get_args(); + if (is_string($list)) { + $list = $args; + } + $ret = array(); + foreach ($list as $value) { + if (is_null($value)) { + continue; + } + $ret[$value] = true; + } + return $ret; + } + + /** + * Lazy load construction of the module after determining whether + * or not it's needed, and also when a finalized configuration object + * is available. + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php new file mode 100644 index 0000000000..1e67c790d0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php @@ -0,0 +1,44 @@ + array('dir' => false) + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $bdo = $this->addElement( + 'bdo', + 'Inline', + 'Inline', + array('Core', 'Lang'), + array( + 'dir' => 'Enum#ltr,rtl', // required + // The Abstract Module specification has the attribute + // inclusions wrong for bdo: bdo allows Lang + ) + ); + $bdo->attr_transform_post[] = new HTMLPurifier_AttrTransform_BdoDir(); + + $this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl'; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php new file mode 100644 index 0000000000..7220c14cc7 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -0,0 +1,32 @@ + array( + 0 => array('Style'), + // 'xml:space' => false, + 'class' => 'Class', + 'id' => 'ID', + 'title' => 'CDATA', + 'contenteditable' => 'ContentEditable', + ), + 'Lang' => array(), + 'I18N' => array( + 0 => array('Lang'), // proprietary, for xml:lang/lang + ), + 'Common' => array( + 0 => array('Core', 'I18N') + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php new file mode 100644 index 0000000000..a9042a3577 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php @@ -0,0 +1,55 @@ + 'URI', + // 'datetime' => 'Datetime', // not implemented + ); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); + } + + // HTML 4.01 specifies that ins/del must not contain block + // elements when used in an inline context, chameleon is + // a complicated workaround to acheive this effect + + // Inline context ! Block context (exclamation mark is + // separator, see getChildDef for parsing) + + /** + * @type bool + */ + public $defines_child_def = true; + + /** + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef_Chameleon + */ + public function getChildDef($def) + { + if ($def->content_model_type != 'chameleon') { + return false; + } + $value = explode('!', $def->content_model); + return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php new file mode 100644 index 0000000000..eb0edcffd5 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php @@ -0,0 +1,194 @@ + 'Form', + 'Inline' => 'Formctrl', + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + if ($config->get('HTML.Forms')) { + $this->safe = true; + } + + $form = $this->addElement( + 'form', + 'Form', + 'Required: Heading | List | Block | fieldset', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accept-charset' => 'Charsets', + 'action*' => 'URI', + 'method' => 'Enum#get,post', + // really ContentType, but these two are the only ones used today + 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', + ) + ); + $form->excludes = array('form' => true); + + $input = $this->addElement( + 'input', + 'Formctrl', + 'Empty', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accesskey' => 'Character', + 'alt' => 'Text', + 'checked' => 'Bool#checked', + 'disabled' => 'Bool#disabled', + 'maxlength' => 'Number', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'size' => 'Number', + 'src' => 'URI#embedded', + 'tabindex' => 'Number', + 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', + 'value' => 'CDATA', + ) + ); + $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); + + $this->addElement( + 'select', + 'Formctrl', + 'Required: optgroup | option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'multiple' => 'Bool#multiple', + 'name' => 'CDATA', + 'size' => 'Number', + 'tabindex' => 'Number', + ) + ); + + $this->addElement( + 'option', + false, + 'Optional: #PCDATA', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label' => 'Text', + 'selected' => 'Bool#selected', + 'value' => 'CDATA', + ) + ); + // It's illegal for there to be more than one selected, but not + // be multiple. Also, no selected means undefined behavior. This might + // be difficult to implement; perhaps an injector, or a context variable. + + $textarea = $this->addElement( + 'textarea', + 'Formctrl', + 'Optional: #PCDATA', + 'Common', + array( + 'accesskey' => 'Character', + 'cols*' => 'Number', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'rows*' => 'Number', + 'tabindex' => 'Number', + ) + ); + $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); + + $button = $this->addElement( + 'button', + 'Formctrl', + 'Optional: #PCDATA | Heading | List | Block | Inline', + 'Common', + array( + 'accesskey' => 'Character', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'tabindex' => 'Number', + 'type' => 'Enum#button,submit,reset', + 'value' => 'CDATA', + ) + ); + + // For exclusions, ideally we'd specify content sets, not literal elements + $button->excludes = $this->makeLookup( + 'form', + 'fieldset', // Form + 'input', + 'select', + 'textarea', + 'label', + 'button', // Formctrl + 'a', // as per HTML 4.01 spec, this is omitted by modularization + 'isindex', + 'iframe' // legacy items + ); + + // Extra exclusion: img usemap="" is not permitted within this element. + // We'll omit this for now, since we don't have any good way of + // indicating it yet. + + // This is HIGHLY user-unfriendly; we need a custom child-def for this + $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); + + $label = $this->addElement( + 'label', + 'Formctrl', + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + // 'for' => 'IDREF', // IDREF not implemented, cannot allow + ) + ); + $label->excludes = array('label' => true); + + $this->addElement( + 'legend', + false, + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + ) + ); + + $this->addElement( + 'optgroup', + false, + 'Required: option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label*' => 'Text', + ) + ); + // Don't forget an injector for . This one's a little complex + // because it maps to multiple elements. + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php new file mode 100644 index 0000000000..72d7a31e68 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php @@ -0,0 +1,40 @@ +addElement( + 'a', + 'Inline', + 'Inline', + 'Common', + array( + // 'accesskey' => 'Character', + // 'charset' => 'Charset', + 'href' => 'URI', + // 'hreflang' => 'LanguageCode', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), + // 'tabindex' => 'Number', + // 'type' => 'ContentType', + ) + ); + $a->formatting = true; + $a->excludes = array('a' => true); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php new file mode 100644 index 0000000000..71dfc77447 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php @@ -0,0 +1,57 @@ +get('HTML.SafeIframe')) { + $this->safe = true; + } + $attrs = array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ); + + if ($config->get('HTML.Trusted')) { + $attrs['allowfullscreen'] = 'Bool#allowfullscreen'; + } + + $this->addElement( + 'iframe', + 'Inline', + 'Flow', + 'Common', + $attrs + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php new file mode 100644 index 0000000000..0f5fdb3baf --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php @@ -0,0 +1,49 @@ +get('HTML.MaxImgLength'); + $img = $this->addElement( + 'img', + 'Inline', + 'Empty', + 'Common', + array( + 'alt*' => 'Text', + // According to the spec, it's Length, but percents can + // be abused, so we allow only Pixels. + 'height' => 'Pixels#' . $max, + 'width' => 'Pixels#' . $max, + 'longdesc' => 'URI', + 'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded + ) + ); + if ($max === null || $config->get('HTML.Trusted')) { + $img->attr['height'] = + $img->attr['width'] = 'Length'; + } + + // kind of strange, but splitting things up would be inefficient + $img->attr_transform_pre[] = + $img->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ImgRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php new file mode 100644 index 0000000000..86b5299579 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php @@ -0,0 +1,186 @@ +addElement( + 'basefont', + 'Inline', + 'Empty', + null, + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + 'id' => 'ID' + ) + ); + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement( + 'dir', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + $this->addElement( + 'font', + 'Inline', + 'Inline', + array('Core', 'I18N'), + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + ) + ); + $this->addElement( + 'menu', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + + $s = $this->addElement('s', 'Inline', 'Inline', 'Common'); + $s->formatting = true; + + $strike = $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $strike->formatting = true; + + $u = $this->addElement('u', 'Inline', 'Inline', 'Common'); + $u->formatting = true; + + // setup modifications to old elements + + $align = 'Enum#left,right,center,justify'; + + $address = $this->addBlankElement('address'); + $address->content_model = 'Inline | #PCDATA | p'; + $address->content_model_type = 'optional'; + $address->child = false; + + $blockquote = $this->addBlankElement('blockquote'); + $blockquote->content_model = 'Flow | #PCDATA'; + $blockquote->content_model_type = 'optional'; + $blockquote->child = false; + + $br = $this->addBlankElement('br'); + $br->attr['clear'] = 'Enum#left,all,right,none'; + + $caption = $this->addBlankElement('caption'); + $caption->attr['align'] = 'Enum#top,bottom,left,right'; + + $div = $this->addBlankElement('div'); + $div->attr['align'] = $align; + + $dl = $this->addBlankElement('dl'); + $dl->attr['compact'] = 'Bool#compact'; + + for ($i = 1; $i <= 6; $i++) { + $h = $this->addBlankElement("h$i"); + $h->attr['align'] = $align; + } + + $hr = $this->addBlankElement('hr'); + $hr->attr['align'] = $align; + $hr->attr['noshade'] = 'Bool#noshade'; + $hr->attr['size'] = 'Pixels'; + $hr->attr['width'] = 'Length'; + + $img = $this->addBlankElement('img'); + $img->attr['align'] = 'IAlign'; + $img->attr['border'] = 'Pixels'; + $img->attr['hspace'] = 'Pixels'; + $img->attr['vspace'] = 'Pixels'; + + // figure out this integer business + + $li = $this->addBlankElement('li'); + $li->attr['value'] = new HTMLPurifier_AttrDef_Integer(); + $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle'; + + $ol = $this->addBlankElement('ol'); + $ol->attr['compact'] = 'Bool#compact'; + $ol->attr['start'] = new HTMLPurifier_AttrDef_Integer(); + $ol->attr['type'] = 'Enum#s:1,i,I,a,A'; + + $p = $this->addBlankElement('p'); + $p->attr['align'] = $align; + + $pre = $this->addBlankElement('pre'); + $pre->attr['width'] = 'Number'; + + // script omitted + + $table = $this->addBlankElement('table'); + $table->attr['align'] = 'Enum#left,center,right'; + $table->attr['bgcolor'] = 'Color'; + + $tr = $this->addBlankElement('tr'); + $tr->attr['bgcolor'] = 'Color'; + + $th = $this->addBlankElement('th'); + $th->attr['bgcolor'] = 'Color'; + $th->attr['height'] = 'Length'; + $th->attr['nowrap'] = 'Bool#nowrap'; + $th->attr['width'] = 'Length'; + + $td = $this->addBlankElement('td'); + $td->attr['bgcolor'] = 'Color'; + $td->attr['height'] = 'Length'; + $td->attr['nowrap'] = 'Bool#nowrap'; + $td->attr['width'] = 'Length'; + + $ul = $this->addBlankElement('ul'); + $ul->attr['compact'] = 'Bool#compact'; + $ul->attr['type'] = 'Enum#square,disc,circle'; + + // "safe" modifications to "unsafe" elements + // WARNING: If you want to add support for an unsafe, legacy + // attribute, make a new TrustedLegacy module with the trusted + // bit set appropriately + + $form = $this->addBlankElement('form'); + $form->content_model = 'Flow | #PCDATA'; + $form->content_model_type = 'optional'; + $form->attr['target'] = 'FrameTarget'; + + $input = $this->addBlankElement('input'); + $input->attr['align'] = 'IAlign'; + + $legend = $this->addBlankElement('legend'); + $legend->attr['align'] = 'LAlign'; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php new file mode 100644 index 0000000000..7a20ff701c --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php @@ -0,0 +1,51 @@ + 'List'); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $ol = $this->addElement('ol', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + $ul = $this->addElement('ul', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + // XXX The wrap attribute is handled by MakeWellFormed. This is all + // quite unsatisfactory, because we generated this + // *specifically* for lists, and now a big chunk of the handling + // is done properly by the List ChildDef. So actually, we just + // want enough information to make autoclosing work properly, + // and then hand off the tricky stuff to the ChildDef. + $ol->wrap = 'li'; + $ul->wrap = 'li'; + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); + + $this->addElement('li', false, 'Flow', 'Common'); + + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php new file mode 100644 index 0000000000..60c0545154 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php @@ -0,0 +1,26 @@ +addBlankElement($name); + $element->attr['name'] = 'CDATA'; + if (!$config->get('HTML.Attr.Name.UseCDATA')) { + $element->attr_transform_post[] = new HTMLPurifier_AttrTransform_NameSync(); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php new file mode 100644 index 0000000000..dc9410a895 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php @@ -0,0 +1,25 @@ +addBlankElement('a'); + $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Nofollow(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php new file mode 100644 index 0000000000..da722253ac --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php @@ -0,0 +1,20 @@ + array( + 'lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php new file mode 100644 index 0000000000..2f9efc5c88 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php @@ -0,0 +1,62 @@ + to cater to legacy browsers: this + * module does not allow this sort of behavior + */ +class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule +{ + /** + * @type string + */ + public $name = 'Object'; + + /** + * @type bool + */ + public $safe = false; + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->addElement( + 'object', + 'Inline', + 'Optional: #PCDATA | Flow | param', + 'Common', + array( + 'archive' => 'URI', + 'classid' => 'URI', + 'codebase' => 'URI', + 'codetype' => 'Text', + 'data' => 'URI', + 'declare' => 'Bool#declare', + 'height' => 'Length', + 'name' => 'CDATA', + 'standby' => 'Text', + 'tabindex' => 'Number', + 'type' => 'ContentType', + 'width' => 'Length' + ) + ); + + $this->addElement( + 'param', + false, + 'Empty', + null, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'type' => 'Text', + 'value' => 'Text', + 'valuetype' => 'Enum#data,ref,object' + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php new file mode 100644 index 0000000000..6458ce9d88 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php @@ -0,0 +1,42 @@ +addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $b = $this->addElement('b', 'Inline', 'Inline', 'Common'); + $b->formatting = true; + $big = $this->addElement('big', 'Inline', 'Inline', 'Common'); + $big->formatting = true; + $i = $this->addElement('i', 'Inline', 'Inline', 'Common'); + $i->formatting = true; + $small = $this->addElement('small', 'Inline', 'Inline', 'Common'); + $small->formatting = true; + $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common'); + $tt->formatting = true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php new file mode 100644 index 0000000000..5ee3c8e67f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php @@ -0,0 +1,40 @@ +addElement( + 'marquee', + 'Inline', + 'Flow', + 'Common', + array( + 'direction' => 'Enum#left,right,up,down', + 'behavior' => 'Enum#alternate', + 'width' => 'Length', + 'height' => 'Length', + 'scrolldelay' => 'Number', + 'scrollamount' => 'Number', + 'loop' => 'Number', + 'bgcolor' => 'Color', + 'hspace' => 'Pixels', + 'vspace' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php new file mode 100644 index 0000000000..a0d48924da --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php @@ -0,0 +1,36 @@ +addElement( + 'ruby', + 'Inline', + 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', + 'Common' + ); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb = $this->addElement('rb', false, 'Inline', 'Common'); + $rb->excludes = array('ruby' => true); + $rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt->excludes = array('ruby' => true); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php new file mode 100644 index 0000000000..04e6689ea6 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php @@ -0,0 +1,40 @@ +get('HTML.MaxImgLength'); + $embed = $this->addElement( + 'embed', + 'Inline', + 'Empty', + 'Common', + array( + 'src*' => 'URI#embedded', + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'allowscriptaccess' => 'Enum#never', + 'allownetworking' => 'Enum#internal', + 'flashvars' => 'Text', + 'wmode' => 'Enum#window,transparent,opaque', + 'name' => 'ID', + ) + ); + $embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php new file mode 100644 index 0000000000..1297f80a39 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php @@ -0,0 +1,62 @@ +get('HTML.MaxImgLength'); + $object = $this->addElement( + 'object', + 'Inline', + 'Optional: param | Flow | #PCDATA', + 'Common', + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'data' => 'URI#embedded', + 'codebase' => new HTMLPurifier_AttrDef_Enum( + array( + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0' + ) + ), + ) + ); + $object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject(); + + $param = $this->addElement( + 'param', + false, + 'Empty', + false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'value' => 'Text' + ) + ); + $param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam(); + $this->info_injector[] = 'SafeObject'; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php new file mode 100644 index 0000000000..aea7584c37 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php @@ -0,0 +1,40 @@ +get('HTML.SafeScripting'); + $script = $this->addElement( + 'script', + 'Inline', + 'Optional:', // Not `Empty` to not allow to autoclose the #i', '', $html); + } + + return $html; + } + + /** + * Takes a string of HTML (fragment or document) and returns the content + * @todo Consider making protected + */ + public function extractBody($html) + { + $matches = array(); + $result = preg_match('|(.*?)]*>(.*)|is', $html, $matches); + if ($result) { + // Make sure it's not in a comment + $comment_start = strrpos($matches[1], ''); + if ($comment_start === false || + ($comment_end !== false && $comment_end > $comment_start)) { + return $matches[2]; + } + } + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php new file mode 100644 index 0000000000..7d579837c4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php @@ -0,0 +1,340 @@ +factory = new HTMLPurifier_TokenFactory(); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] + */ + public function tokenizeHTML($html, $config, $context) + { + $html = $this->normalize($html, $config, $context); + + // attempt to armor stray angled brackets that cannot possibly + // form tags and thus are probably being used as emoticons + if ($config->get('Core.AggressivelyFixLt')) { + $char = '[^a-z!\/]'; + $comment = "/|\z)/is"; + $html = preg_replace_callback($comment, array($this, 'callbackArmorCommentEntities'), $html); + do { + $old = $html; + $html = preg_replace("/<($char)/i", '<\\1', $html); + } while ($html !== $old); + $html = preg_replace_callback($comment, array($this, 'callbackUndoCommentSubst'), $html); // fix comments + } + + // preprocess html, essential for UTF-8 + $html = $this->wrapHTML($html, $config, $context); + + $doc = new DOMDocument(); + $doc->encoding = 'UTF-8'; // theoretically, the above has this covered + + $options = 0; + if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) { + $options |= LIBXML_PARSEHUGE; + } + if ($config->get('Core.RemoveBlanks') && defined('LIBXML_NOBLANKS')) { + $options |= LIBXML_NOBLANKS; + } + + set_error_handler(array($this, 'muteErrorHandler')); + // loadHTML() fails on PHP 5.3 when second parameter is given + if ($options) { + $doc->loadHTML($html, $options); + } else { + $doc->loadHTML($html); + } + restore_error_handler(); + + $body = $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0); // + + $div = $body->getElementsByTagName('div')->item(0); //
+ $tokens = array(); + $this->tokenizeDOM($div, $tokens, $config); + // If the div has a sibling, that means we tripped across + // a premature
tag. So remove the div we parsed, + // and then tokenize the rest of body. We can't tokenize + // the sibling directly as we'll lose the tags in that case. + if ($div->nextSibling) { + $body->removeChild($div); + $this->tokenizeDOM($body, $tokens, $config); + } + return $tokens; + } + + /** + * Iterative function that tokenizes a node, putting it into an accumulator. + * To iterate is human, to recurse divine - L. Peter Deutsch + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + */ + protected function tokenizeDOM($node, &$tokens, $config) + { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingNodes = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + $collect = $level > 0 ? true : false; + $needEndingTag = $this->createStartNode($node, $tokens, $collect, $config); + if ($needEndingTag) { + $closingNodes[$level][] = $node; + } + if ($node->childNodes && $node->childNodes->length) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->childNodes as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingNodes[$level])) { + while ($node = array_pop($closingNodes[$level])) { + $this->createEndNode($node, $tokens); + } + } + } while ($level > 0); + } + + /** + * Portably retrieve the tag name of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getTagName($node) + { + if (isset($node->tagName)) { + return $node->tagName; + } else if (isset($node->nodeName)) { + return $node->nodeName; + } else if (isset($node->localName)) { + return $node->localName; + } + return null; + } + + /** + * Portably retrieve the data of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getData($node) + { + if (isset($node->data)) { + return $node->data; + } else if (isset($node->nodeValue)) { + return $node->nodeValue; + } else if (isset($node->textContent)) { + return $node->textContent; + } + return null; + } + + + /** + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + * @param bool $collect Says whether or start and close are collected, set to + * false at first recursion because it's the implicit DIV + * tag you're dealing with. + * @return bool if the token needs an endtoken + * @todo data and tagName properties don't seem to exist in DOMNode? + */ + protected function createStartNode($node, &$tokens, $collect, $config) + { + // intercept non element nodes. WE MUST catch all of them, + // but we're not getting the character reference nodes because + // those should have been preprocessed + if ($node->nodeType === XML_TEXT_NODE) { + $data = $this->getData($node); // Handle variable data property + if ($data !== null) { + $tokens[] = $this->factory->createText($data); + } + return false; + } elseif ($node->nodeType === XML_CDATA_SECTION_NODE) { + // undo libxml's special treatment of )#si', + array($this, 'scriptCallback'), + $html + ); + } + + $html = $this->normalize($html, $config, $context); + + $cursor = 0; // our location in the text + $inside_tag = false; // whether or not we're parsing the inside of a tag + $array = array(); // result array + + // This is also treated to mean maintain *column* numbers too + $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); + + if ($maintain_line_numbers === null) { + // automatically determine line numbering by checking + // if error collection is on + $maintain_line_numbers = $config->get('Core.CollectErrors'); + } + + if ($maintain_line_numbers) { + $current_line = 1; + $current_col = 0; + $length = strlen($html); + } else { + $current_line = false; + $current_col = false; + $length = false; + } + $context->register('CurrentLine', $current_line); + $context->register('CurrentCol', $current_col); + $nl = "\n"; + // how often to manually recalculate. This will ALWAYS be right, + // but it's pretty wasteful. Set to 0 to turn off + $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // for testing synchronization + $loops = 0; + + while (++$loops) { + // $cursor is either at the start of a token, or inside of + // a tag (i.e. there was a < immediately before it), as indicated + // by $inside_tag + + if ($maintain_line_numbers) { + // $rcursor, however, is always at the start of a token. + $rcursor = $cursor - (int)$inside_tag; + + // Column number is cheap, so we calculate it every round. + // We're interested at the *end* of the newline string, so + // we need to add strlen($nl) == 1 to $nl_pos before subtracting it + // from our "rcursor" position. + $nl_pos = strrpos($html, $nl, $rcursor - $length); + $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); + + // recalculate lines + if ($synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0) { // time to synchronize! + $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); + } + } + + $position_next_lt = strpos($html, '<', $cursor); + $position_next_gt = strpos($html, '>', $cursor); + + // triggers on "asdf" but not "asdf " + // special case to set up context + if ($position_next_lt === $cursor) { + $inside_tag = true; + $cursor++; + } + + if (!$inside_tag && $position_next_lt !== false) { + // We are not inside tag and there still is another tag to parse + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor, + $position_next_lt - $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); + } + $array[] = $token; + $cursor = $position_next_lt + 1; + $inside_tag = true; + continue; + } elseif (!$inside_tag) { + // We are not inside tag but there are no more tags + // If we're already at the end, break + if ($cursor === strlen($html)) { + break; + } + // Create Text of rest of string + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + $array[] = $token; + break; + } elseif ($inside_tag && $position_next_gt !== false) { + // We are in tag and it is well formed + // Grab the internals of the tag + $strlen_segment = $position_next_gt - $cursor; + + if ($strlen_segment < 1) { + // there's nothing to process! + $token = new HTMLPurifier_Token_Text('<'); + $cursor++; + continue; + } + + $segment = substr($html, $cursor, $strlen_segment); + + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + + // Check if it's a comment + if (substr($segment, 0, 3) === '!--') { + // re-determine segment length, looking for --> + $position_comment_end = strpos($html, '-->', $cursor); + if ($position_comment_end === false) { + // uh oh, we have a comment that extends to + // infinity. Can't be helped: set comment + // end position to end of string + if ($e) { + $e->send(E_WARNING, 'Lexer: Unclosed comment'); + } + $position_comment_end = strlen($html); + $end = true; + } else { + $end = false; + } + $strlen_segment = $position_comment_end - $cursor; + $segment = substr($html, $cursor, $strlen_segment); + $token = new + HTMLPurifier_Token_Comment( + substr( + $segment, + 3, + $strlen_segment - 3 + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); + } + $array[] = $token; + $cursor = $end ? $position_comment_end : $position_comment_end + 3; + $inside_tag = false; + continue; + } + + // Check if it's an end tag + $is_end_tag = (strpos($segment, '/') === 0); + if ($is_end_tag) { + $type = substr($segment, 1); + $token = new HTMLPurifier_Token_End($type); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Check leading character is alnum, if not, we may + // have accidently grabbed an emoticon. Translate into + // text and go our merry way + if (!ctype_alpha($segment[0])) { + // XML: $segment[0] !== '_' && $segment[0] !== ':' + if ($e) { + $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + } + $token = new HTMLPurifier_Token_Text('<'); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + continue; + } + + // Check if it is explicitly self closing, if so, remove + // trailing slash. Remember, we could have a tag like
, so + // any later token processing scripts must convert improperly + // classified EmptyTags from StartTags. + $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1); + if ($is_self_closing) { + $strlen_segment--; + $segment = substr($segment, 0, $strlen_segment); + } + + // Check if there are any attributes + $position_first_space = strcspn($segment, $this->_whitespace); + + if ($position_first_space >= $strlen_segment) { + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($segment); + } else { + $token = new HTMLPurifier_Token_Start($segment); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Grab out all the data + $type = substr($segment, 0, $position_first_space); + $attribute_string = + trim( + substr( + $segment, + $position_first_space + ) + ); + if ($attribute_string) { + $attr = $this->parseAttributeString( + $attribute_string, + $config, + $context + ); + } else { + $attr = array(); + } + + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($type, $attr); + } else { + $token = new HTMLPurifier_Token_Start($type, $attr); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $cursor = $position_next_gt + 1; + $inside_tag = false; + continue; + } else { + // inside tag, but there's no ending > sign + if ($e) { + $e->send(E_WARNING, 'Lexer: Missing gt'); + } + $token = new + HTMLPurifier_Token_Text( + '<' . + $this->parseText( + substr($html, $cursor), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + // no cursor scroll? Hmm... + $array[] = $token; + break; + } + break; + } + + $context->destroy('CurrentLine'); + $context->destroy('CurrentCol'); + return $array; + } + + /** + * PHP 5.0.x compatible substr_count that implements offset and length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int $length + * @return int + */ + protected function substrCount($haystack, $needle, $offset, $length) + { + static $oldVersion; + if ($oldVersion === null) { + $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); + } + if ($oldVersion) { + $haystack = substr($haystack, $offset, $length); + return substr_count($haystack, $needle); + } else { + return substr_count($haystack, $needle, $offset, $length); + } + } + + /** + * Takes the inside of an HTML tag and makes an assoc array of attributes. + * + * @param string $string Inside of tag excluding name. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array Assoc array of attributes. + */ + public function parseAttributeString($string, $config, $context) + { + $string = (string)$string; // quick typecast + + if ($string == '') { + return array(); + } // no attributes + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // let's see if we can abort as quickly as possible + // one equal sign, no spaces => one attribute + $num_equal = substr_count($string, '='); + $has_space = strpos($string, ' '); + if ($num_equal === 0 && !$has_space) { + // bool attribute + return array($string => $string); + } elseif ($num_equal === 1 && !$has_space) { + // only one attribute + list($key, $quoted_value) = explode('=', $string); + $quoted_value = trim($quoted_value); + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + return array(); + } + if (!$quoted_value) { + return array($key => ''); + } + $first_char = @$quoted_value[0]; + $last_char = @$quoted_value[strlen($quoted_value) - 1]; + + $same_quote = ($first_char == $last_char); + $open_quote = ($first_char == '"' || $first_char == "'"); + + if ($same_quote && $open_quote) { + // well behaved + $value = substr($quoted_value, 1, strlen($quoted_value) - 2); + } else { + // not well behaved + if ($open_quote) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing end quote'); + } + $value = substr($quoted_value, 1); + } else { + $value = $quoted_value; + } + } + if ($value === false) { + $value = ''; + } + return array($key => $this->parseAttr($value, $config)); + } + + // setup loop environment + $array = array(); // return assoc array of attributes + $cursor = 0; // current position in string (moves forward) + $size = strlen($string); // size of the string (stays the same) + + // if we have unquoted attributes, the parser expects a terminating + // space, so let's guarantee that there's always a terminating space. + $string .= ' '; + + $old_cursor = -1; + while ($cursor < $size) { + if ($old_cursor >= $cursor) { + throw new Exception("Infinite loop detected"); + } + $old_cursor = $cursor; + + $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); + // grab the key + + $key_begin = $cursor; //we're currently at the start of the key + + // scroll past all characters that are the key (not whitespace or =) + $cursor += strcspn($string, $this->_whitespace . '=', $cursor); + + $key_end = $cursor; // now at the end of the key + + $key = substr($string, $key_begin, $key_end - $key_begin); + + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + continue; // empty key + } + + // scroll past all whitespace + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor >= $size) { + $array[$key] = $key; + break; + } + + // if the next character is an equal sign, we've got a regular + // pair, otherwise, it's a bool attribute + $first_char = @$string[$cursor]; + + if ($first_char == '=') { + // key="value" + + $cursor++; + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor === false) { + $array[$key] = ''; + break; + } + + // we might be in front of a quote right now + + $char = @$string[$cursor]; + + if ($char == '"' || $char == "'") { + // it's quoted, end bound is $char + $cursor++; + $value_begin = $cursor; + $cursor = strpos($string, $char, $cursor); + $value_end = $cursor; + } else { + // it's not quoted, end bound is whitespace + $value_begin = $cursor; + $cursor += strcspn($string, $this->_whitespace, $cursor); + $value_end = $cursor; + } + + // we reached a premature end + if ($cursor === false) { + $cursor = $size; + $value_end = $cursor; + } + + $value = substr($string, $value_begin, $value_end - $value_begin); + if ($value === false) { + $value = ''; + } + $array[$key] = $this->parseAttr($value, $config); + $cursor++; + } else { + // boolattr + if ($key !== '') { + $array[$key] = $key; + } else { + // purely theoretical + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + } + } + } + return $array; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 0000000000..1564f283dc --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,4788 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context, false /* no div */); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0) // + , + $tokens, $config + ); + return $tokens; + } +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 +{ + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array( + 'AElig;', + 'AElig', + 'AMP;', + 'AMP', + 'Aacute;', + 'Aacute', + 'Acirc;', + 'Acirc', + 'Agrave;', + 'Agrave', + 'Alpha;', + 'Aring;', + 'Aring', + 'Atilde;', + 'Atilde', + 'Auml;', + 'Auml', + 'Beta;', + 'COPY;', + 'COPY', + 'Ccedil;', + 'Ccedil', + 'Chi;', + 'Dagger;', + 'Delta;', + 'ETH;', + 'ETH', + 'Eacute;', + 'Eacute', + 'Ecirc;', + 'Ecirc', + 'Egrave;', + 'Egrave', + 'Epsilon;', + 'Eta;', + 'Euml;', + 'Euml', + 'GT;', + 'GT', + 'Gamma;', + 'Iacute;', + 'Iacute', + 'Icirc;', + 'Icirc', + 'Igrave;', + 'Igrave', + 'Iota;', + 'Iuml;', + 'Iuml', + 'Kappa;', + 'LT;', + 'LT', + 'Lambda;', + 'Mu;', + 'Ntilde;', + 'Ntilde', + 'Nu;', + 'OElig;', + 'Oacute;', + 'Oacute', + 'Ocirc;', + 'Ocirc', + 'Ograve;', + 'Ograve', + 'Omega;', + 'Omicron;', + 'Oslash;', + 'Oslash', + 'Otilde;', + 'Otilde', + 'Ouml;', + 'Ouml', + 'Phi;', + 'Pi;', + 'Prime;', + 'Psi;', + 'QUOT;', + 'QUOT', + 'REG;', + 'REG', + 'Rho;', + 'Scaron;', + 'Sigma;', + 'THORN;', + 'THORN', + 'TRADE;', + 'Tau;', + 'Theta;', + 'Uacute;', + 'Uacute', + 'Ucirc;', + 'Ucirc', + 'Ugrave;', + 'Ugrave', + 'Upsilon;', + 'Uuml;', + 'Uuml', + 'Xi;', + 'Yacute;', + 'Yacute', + 'Yuml;', + 'Zeta;', + 'aacute;', + 'aacute', + 'acirc;', + 'acirc', + 'acute;', + 'acute', + 'aelig;', + 'aelig', + 'agrave;', + 'agrave', + 'alefsym;', + 'alpha;', + 'amp;', + 'amp', + 'and;', + 'ang;', + 'apos;', + 'aring;', + 'aring', + 'asymp;', + 'atilde;', + 'atilde', + 'auml;', + 'auml', + 'bdquo;', + 'beta;', + 'brvbar;', + 'brvbar', + 'bull;', + 'cap;', + 'ccedil;', + 'ccedil', + 'cedil;', + 'cedil', + 'cent;', + 'cent', + 'chi;', + 'circ;', + 'clubs;', + 'cong;', + 'copy;', + 'copy', + 'crarr;', + 'cup;', + 'curren;', + 'curren', + 'dArr;', + 'dagger;', + 'darr;', + 'deg;', + 'deg', + 'delta;', + 'diams;', + 'divide;', + 'divide', + 'eacute;', + 'eacute', + 'ecirc;', + 'ecirc', + 'egrave;', + 'egrave', + 'empty;', + 'emsp;', + 'ensp;', + 'epsilon;', + 'equiv;', + 'eta;', + 'eth;', + 'eth', + 'euml;', + 'euml', + 'euro;', + 'exist;', + 'fnof;', + 'forall;', + 'frac12;', + 'frac12', + 'frac14;', + 'frac14', + 'frac34;', + 'frac34', + 'frasl;', + 'gamma;', + 'ge;', + 'gt;', + 'gt', + 'hArr;', + 'harr;', + 'hearts;', + 'hellip;', + 'iacute;', + 'iacute', + 'icirc;', + 'icirc', + 'iexcl;', + 'iexcl', + 'igrave;', + 'igrave', + 'image;', + 'infin;', + 'int;', + 'iota;', + 'iquest;', + 'iquest', + 'isin;', + 'iuml;', + 'iuml', + 'kappa;', + 'lArr;', + 'lambda;', + 'lang;', + 'laquo;', + 'laquo', + 'larr;', + 'lceil;', + 'ldquo;', + 'le;', + 'lfloor;', + 'lowast;', + 'loz;', + 'lrm;', + 'lsaquo;', + 'lsquo;', + 'lt;', + 'lt', + 'macr;', + 'macr', + 'mdash;', + 'micro;', + 'micro', + 'middot;', + 'middot', + 'minus;', + 'mu;', + 'nabla;', + 'nbsp;', + 'nbsp', + 'ndash;', + 'ne;', + 'ni;', + 'not;', + 'not', + 'notin;', + 'nsub;', + 'ntilde;', + 'ntilde', + 'nu;', + 'oacute;', + 'oacute', + 'ocirc;', + 'ocirc', + 'oelig;', + 'ograve;', + 'ograve', + 'oline;', + 'omega;', + 'omicron;', + 'oplus;', + 'or;', + 'ordf;', + 'ordf', + 'ordm;', + 'ordm', + 'oslash;', + 'oslash', + 'otilde;', + 'otilde', + 'otimes;', + 'ouml;', + 'ouml', + 'para;', + 'para', + 'part;', + 'permil;', + 'perp;', + 'phi;', + 'pi;', + 'piv;', + 'plusmn;', + 'plusmn', + 'pound;', + 'pound', + 'prime;', + 'prod;', + 'prop;', + 'psi;', + 'quot;', + 'quot', + 'rArr;', + 'radic;', + 'rang;', + 'raquo;', + 'raquo', + 'rarr;', + 'rceil;', + 'rdquo;', + 'real;', + 'reg;', + 'reg', + 'rfloor;', + 'rho;', + 'rlm;', + 'rsaquo;', + 'rsquo;', + 'sbquo;', + 'scaron;', + 'sdot;', + 'sect;', + 'sect', + 'shy;', + 'shy', + 'sigma;', + 'sigmaf;', + 'sim;', + 'spades;', + 'sub;', + 'sube;', + 'sum;', + 'sup1;', + 'sup1', + 'sup2;', + 'sup2', + 'sup3;', + 'sup3', + 'sup;', + 'supe;', + 'szlig;', + 'szlig', + 'tau;', + 'there4;', + 'theta;', + 'thetasym;', + 'thinsp;', + 'thorn;', + 'thorn', + 'tilde;', + 'times;', + 'times', + 'trade;', + 'uArr;', + 'uacute;', + 'uacute', + 'uarr;', + 'ucirc;', + 'ucirc', + 'ugrave;', + 'ugrave', + 'uml;', + 'uml', + 'upsih;', + 'upsilon;', + 'uuml;', + 'uuml', + 'weierp;', + 'xi;', + 'yacute;', + 'yacute', + 'yen;', + 'yen', + 'yuml;', + 'yuml', + 'zeta;', + 'zwj;', + 'zwnj;' + ); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) + { + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while ($this->state !== null) { + $this->{$this->state . 'State'}(); + } + } + + public function save() + { + return $this->tree->save(); + } + + private function char() + { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) + { + if ($s + $l < $this->EOF) { + if ($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) + { + return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() + { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif ($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if (($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->' + ) { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + } elseif ($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif ($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + ) + ); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + $this->state = 'data'; + } + } + + private function entityDataState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() + { + switch ($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if ($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if ($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<>' + ) + ); + + $this->state = 'data'; + + } elseif ($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() + { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match( + '/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node)) + ) || $this->EOF === $this->char))) + ) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif ($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() + { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken( + array( + 'data' => $data, + 'type' => self::COMMENT + ) + ); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if ($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() + { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if ($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-' . $char; + $this->state = 'comment'; + } + } + + private function commentEndState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '-') { + $this->token['data'] .= '-'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--' . $char; + $this->state = 'comment'; + } + } + + private function doctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif ($char === '>') { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() + { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch ($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch ($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens below. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for ($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if (in_array($id, $this->entities)) { + if ($e_name[$c - 1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens below. + break; + } + + if (!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&' . rtrim($entity, ';') . ';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) + { + $emit = $this->tree->emitToken($token); + + if (is_int($emit)) { + $this->content_model = $emit; + + } elseif ($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() + { + $this->state = null; + $this->tree->emitToken( + array( + 'type' => self::EOF + ) + ); + } +} + +class HTML5TreeConstructer +{ + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th'); + private $formatting = array( + 'a', + 'b', + 'big', + 'em', + 'font', + 'i', + 'nobr', + 's', + 'small', + 'strike', + 'strong', + 'tt', + 'u' + ); + private $special = array( + 'address', + 'area', + 'base', + 'basefont', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'center', + 'col', + 'colgroup', + 'dd', + 'dir', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'hr', + 'iframe', + 'image', + 'img', + 'input', + 'isindex', + 'li', + 'link', + 'listing', + 'menu', + 'meta', + 'noembed', + 'noframes', + 'noscript', + 'ol', + 'optgroup', + 'option', + 'p', + 'param', + 'plaintext', + 'pre', + 'script', + 'select', + 'spacer', + 'style', + 'tbody', + 'textarea', + 'tfoot', + 'thead', + 'title', + 'tr', + 'ul', + 'wbr' + ); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() + { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) + { + switch ($this->phase) { + case self::INIT_PHASE: + return $this->initPhase($token); + break; + case self::ROOT_PHASE: + return $this->rootElementPhase($token); + break; + case self::MAIN_PHASE: + return $this->mainPhase($token); + break; + case self::END_PHASE : + return $this->trailingEndPhase($token); + break; + } + } + + private function initPhase($token) + { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if ((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) + ) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif (isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif (isset($token['data']) && preg_match( + '/^[\t\n\x0b\x0c ]+$/', + $token['data'] + ) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) + { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif (($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF + ) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) + { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach ($token['attr'] as $attr) { + if (!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch ($this->mode) { + case self::BEFOR_HEAD: + return $this->beforeHead($token); + break; + case self::IN_HEAD: + return $this->inHead($token); + break; + case self::AFTER_HEAD: + return $this->afterHead($token); + break; + case self::IN_BODY: + return $this->inBody($token); + break; + case self::IN_TABLE: + return $this->inTable($token); + break; + case self::IN_CAPTION: + return $this->inCaption($token); + break; + case self::IN_CGROUP: + return $this->inColumnGroup($token); + break; + case self::IN_TBODY: + return $this->inTableBody($token); + break; + case self::IN_ROW: + return $this->inRow($token); + break; + case self::IN_CELL: + return $this->inCell($token); + break; + case self::IN_SELECT: + return $this->inSelect($token); + break; + case self::AFTER_BODY: + return $this->afterBody($token); + break; + case self::IN_FRAME: + return $this->inFrameset($token); + break; + case self::AFTR_FRAME: + return $this->afterFrameset($token); + break; + case self::END_PHASE: + return $this->trailingEndPhase($token); + break; + } + } + } + + private function beforeHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif ($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match( + '/^[\t\n\x0b\x0c ]$/', + $token['data'] + )) + ) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead( + array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif ($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array( + end($this->stack)->nodeName, + array('title', 'style', 'script') + )) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script')) + ) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta') + ) + ) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html') + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead( + array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + ) + ); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title') + ) + ) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inBody($token); + } + } + + private function inBody($token) + { + /* Handle the token as follows: */ + + switch ($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch ($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': + case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': + case 'link': + case 'meta': + case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach ($token['attr'] as $attr) { + if (!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'p': + case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if ($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': + case 'dd': + case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + $stack_length = count($this->stack) - 1; + + for ($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if ($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt')) + ) { + for ($x = $stack_length; $x >= $n; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if ($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div' + ) { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for ($n = $leng - 1; $n >= 0; $n--) { + if ($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken( + array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + ) + ); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if ($this->elementInScope('button')) { + $this->inBody( + array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': + case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'img': + case 'param': + case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if ($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody( + array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + ) + ); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + ) + ); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': + case 'noembed': + case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'frameset': + case 'head': + case 'option': + case 'optgroup': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': + case 'section': + case 'nav': + case 'article': + case 'aside': + case 'header': + case 'footer': + case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch ($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif (end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'pre': + case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if (end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if ($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': + case 'dt': + case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if ($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while ($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while (true) { + for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if ($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if (!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name'])) + ) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif (isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for ($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if ($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if (!isset($furthest_block)) { + for ($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if ($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while (true) { + for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if (!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if ($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif ($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if ($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while ($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': + case 'marquee': + case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'hr': + case 'iframe': + case 'image': + case 'img': + case 'input': + case 'isindex': + case 'noembed': + case 'noframes': + case 'param': + case 'select': + case 'spacer': + case 'table': + case 'textarea': + case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if ($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for ($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if ($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) + { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col' + ) { + $this->inTable( + array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('tbody', 'tfoot', 'thead') + ) + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr')) + ) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable( + array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table' + ) { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable( + array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'caption', + 'col', + 'colgroup', + 'html', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if (in_array( + end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif (!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif (isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE) + ) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) + { + /* An end tag whose tag name is "caption" */ + if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + )) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') + ) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption( + array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'col', + 'colgroup', + 'html', + 'tbody', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) + { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup' + ) { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup( + array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + } + } + + private function inTableBody($token) + { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody( + array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead') + )) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table') + ) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody( + array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) + { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) + { + /* An end tag whose tag name is one of: "td", "th" */ + if ($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th') + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html') + ) + ) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) + { + /* Handle the token as follows: */ + + /* A character token */ + if ($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if (end($this->stack)->nodeName === 'optgroup') { + $this->inSelect( + array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup' + ) { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup' + ) { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if ($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if (end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif ($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG + ) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif (in_array( + $token['name'], + array( + 'caption', + 'table', + 'tbody', + 'tfoot', + 'thead', + 'tr', + 'td', + 'th' + ) + ) && $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if ($this->elementInScope($token['name'], true)) { + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG + ) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG + ) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif ($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG + ) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif ($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG + ) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) + { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) + { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') { + $token['name'] = 'span'; + } // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach ($token['attr'] as $attr) { + if (!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], (string)$attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) + { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) + { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) + { + if ($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif ($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null + ) { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) { + $this->foster_parent->insertBefore($node, $table); + } else { + $this->foster_parent->appendChild($node); + } + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) + { + if (is_array($el)) { + foreach ($el as $element) { + if ($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for ($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if ($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif ($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif ($table === true && in_array( + $node->tagName, + array( + 'caption', + 'td', + 'th', + 'button', + 'marquee', + 'object' + ) + ) + ) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif ($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() + { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if ($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for ($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if ($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while (true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if (isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if (end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() + { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while (true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if ($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) + { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while (in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) + { + $name = $node->tagName; + if (in_array($name, $this->special)) { + return self::SPECIAL; + } elseif (in_array($name, $this->scoping)) { + return self::SCOPING; + } elseif (in_array($name, $this->formatting)) { + return self::FORMATTING; + } else { + return self::PHRASING; + } + } + + private function clearStackToTableContext($elements) + { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while (true) { + $node = end($this->stack)->nodeName; + + if (in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() + { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for ($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if ($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if ($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif ($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif ($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif ($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif ($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif ($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif ($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() + { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach (array('td', 'th') as $cell) { + if ($this->elementInScope($cell, true)) { + $this->inCell( + array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + ) + ); + + break; + } + } + } + + public function save() + { + return $this->dom; + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php new file mode 100644 index 0000000000..3995fec9fe --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php @@ -0,0 +1,49 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null); + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php new file mode 100644 index 0000000000..6cbf56dada --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php @@ -0,0 +1,59 @@ + form or the form, i.e. + * is it a pair of start/end tokens or an empty token. + * @bool + */ + public $empty = false; + + public $endCol = null, $endLine = null, $endArmor = array(); + + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) { + $this->name = $name; + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toTokenPair() { + // XXX inefficiency here, normalization is not necessary + if ($this->empty) { + return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null); + } else { + $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor); + $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor); + //$end->start = $start; + return array($start, $end); + } + } +} + diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php new file mode 100644 index 0000000000..aec9166473 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php @@ -0,0 +1,54 @@ +data = $data; + $this->is_whitespace = $is_whitespace; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php new file mode 100644 index 0000000000..18c8bbb00a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php @@ -0,0 +1,111 @@ +preserve[$i] = true; + } + for ($i = 65; $i <= 90; $i++) { // upper-case + $this->preserve[$i] = true; + } + for ($i = 97; $i <= 122; $i++) { // lower-case + $this->preserve[$i] = true; + } + $this->preserve[45] = true; // Dash - + $this->preserve[46] = true; // Period . + $this->preserve[95] = true; // Underscore _ + $this->preserve[126]= true; // Tilde ~ + + // extra letters not to escape + if ($preserve !== false) { + for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { + $this->preserve[ord($preserve[$i])] = true; + } + } + } + + /** + * Our replacement for urlencode, it encodes all non-reserved characters, + * as well as any extra characters that were instructed to be preserved. + * @note + * Assumes that the string has already been normalized, making any + * and all percent escape sequences valid. Percents will not be + * re-escaped, regardless of their status in $preserve + * @param string $string String to be encoded + * @return string Encoded string. + */ + public function encode($string) + { + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) { + $ret .= '%' . sprintf('%02X', $int); + } else { + $ret .= $string[$i]; + } + } + return $ret; + } + + /** + * Fix up percent-encoding by decoding unreserved characters and normalizing. + * @warning This function is affected by $preserve, even though the + * usual desired behavior is for this not to preserve those + * characters. Be careful when reusing instances of PercentEncoder! + * @param string $string String to normalize + * @return string + */ + public function normalize($string) + { + if ($string == '') { + return ''; + } + $parts = explode('%', $string); + $ret = array_shift($parts); + foreach ($parts as $part) { + $length = strlen($part); + if ($length < 2) { + $ret .= '%25' . $part; + continue; + } + $encoding = substr($part, 0, 2); + $text = substr($part, 2); + if (!ctype_xdigit($encoding)) { + $ret .= '%25' . $part; + continue; + } + $int = hexdec($encoding); + if (isset($this->preserve[$int])) { + $ret .= chr($int) . $text; + continue; + } + $encoding = strtoupper($encoding); + $ret .= '%' . $encoding . $text; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php new file mode 100644 index 0000000000..549e4cea1e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php @@ -0,0 +1,218 @@ +getAll(); + $context = new HTMLPurifier_Context(); + $this->generator = new HTMLPurifier_Generator($config, $context); + } + + /** + * Main function that renders object or aspect of that object + * @note Parameters vary depending on printer + */ + // function render() {} + + /** + * Returns a start tag + * @param string $tag Tag name + * @param array $attr Attribute array + * @return string + */ + protected function start($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); + } + + /** + * Returns an end tag + * @param string $tag Tag name + * @return string + */ + protected function end($tag) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_End($tag) + ); + } + + /** + * Prints a complete element with content inside + * @param string $tag Tag name + * @param string $contents Element contents + * @param array $attr Tag attributes + * @param bool $escape whether or not to escape contents + * @return string + */ + protected function element($tag, $contents, $attr = array(), $escape = true) + { + return $this->start($tag, $attr) . + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); + } + + /** + * @param string $tag + * @param array $attr + * @return string + */ + protected function elementEmpty($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Empty($tag, $attr) + ); + } + + /** + * @param string $text + * @return string + */ + protected function text($text) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Text($text) + ); + } + + /** + * Prints a simple key/value row in a table. + * @param string $name Key + * @param mixed $value Value + * @return string + */ + protected function row($name, $value) + { + if (is_bool($value)) { + $value = $value ? 'On' : 'Off'; + } + return + $this->start('tr') . "\n" . + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr'); + } + + /** + * Escapes a string for HTML output. + * @param string $string String to escape + * @return string + */ + protected function escape($string) + { + $string = HTMLPurifier_Encoder::cleanUTF8($string); + $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); + return $string; + } + + /** + * Takes a list of strings and turns them into a single list + * @param string[] $array List of strings + * @param bool $polite Bool whether or not to add an end before the last + * @return string + */ + protected function listify($array, $polite = false) + { + if (empty($array)) { + return 'None'; + } + $ret = ''; + $i = count($array); + foreach ($array as $value) { + $i--; + $ret .= $value; + if ($i > 0 && !($polite && $i == 1)) { + $ret .= ', '; + } + if ($polite && $i == 1) { + $ret .= 'and '; + } + } + return $ret; + } + + /** + * Retrieves the class of an object without prefixes, as well as metadata + * @param object $obj Object to determine class of + * @param string $sec_prefix Further prefix to remove + * @return string + */ + protected function getClass($obj, $sec_prefix = '') + { + static $five = null; + if ($five === null) { + $five = version_compare(PHP_VERSION, '5', '>='); + } + $prefix = 'HTMLPurifier_' . $sec_prefix; + if (!$five) { + $prefix = strtolower($prefix); + } + $class = str_replace($prefix, '', get_class($obj)); + $lclass = strtolower($class); + $class .= '('; + switch ($lclass) { + case 'enum': + $values = array(); + foreach ($obj->valid_values as $value => $bool) { + $values[] = $value; + } + $class .= implode(', ', $values); + break; + case 'css_composite': + $values = array(); + foreach ($obj->defs as $def) { + $values[] = $this->getClass($def, $sec_prefix); + } + $class .= implode(', ', $values); + break; + case 'css_multiple': + $class .= $this->getClass($obj->single, $sec_prefix) . ', '; + $class .= $obj->max; + break; + case 'css_denyelementdecorator': + $class .= $this->getClass($obj->def, $sec_prefix) . ', '; + $class .= $obj->element; + break; + case 'css_importantdecorator': + $class .= $this->getClass($obj->def, $sec_prefix); + if ($obj->allow) { + $class .= ', !important'; + } + break; + } + $class .= ')'; + return $class; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php new file mode 100644 index 0000000000..29505fe12d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php @@ -0,0 +1,44 @@ +def = $config->getCSSDefinition(); + $ret = ''; + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + $ret .= $this->start('table'); + + $ret .= $this->element('caption', 'Properties ($info)'); + + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Property', array('class' => 'heavy')); + $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + + ksort($this->def->info); + foreach ($this->def->info as $property => $obj) { + $name = $this->getClass($obj, 'AttrDef_'); + $ret .= $this->row($property, $name); + } + + $ret .= $this->end('table'); + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css new file mode 100644 index 0000000000..3ff1a88aa4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css @@ -0,0 +1,10 @@ + +.hp-config {} + +.hp-config tbody th {text-align:right; padding-right:0.5em;} +.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} +.hp-config .namespace th {text-align:center;} +.hp-config .verbose {display:none;} +.hp-config .controls {text-align:center;} + +/* vim: et sw=4 sts=4 */ diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js new file mode 100644 index 0000000000..cba00c9b80 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js @@ -0,0 +1,5 @@ +function toggleWriteability(id_of_patient, checked) { + document.getElementById(id_of_patient).disabled = checked; +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php new file mode 100644 index 0000000000..4c3ce1758e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php @@ -0,0 +1,456 @@ +docURL = $doc_url; + $this->name = $name; + $this->compress = $compress; + // initialize sub-printers + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::C_BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + } + + /** + * Sets default column and row size for textareas in sub-printers + * @param $cols Integer columns of textarea, null to use default + * @param $rows Integer rows of textarea, null to use default + */ + public function setTextareaDimensions($cols = null, $rows = null) + { + if ($cols) { + $this->fields['default']->cols = $cols; + } + if ($rows) { + $this->fields['default']->rows = $rows; + } + } + + /** + * Retrieves styling, in case it is not accessible by webserver + */ + public static function getCSS() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); + } + + /** + * Retrieves JavaScript, in case it is not accessible by webserver + */ + public static function getJavaScript() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); + } + + /** + * Returns HTML output for a configuration form + * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array + * where [0] has an HTML namespace and [1] is being rendered. + * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. + * @param bool $render_controls + * @return string + */ + public function render($config, $allowed = true, $render_controls = true) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + + $this->config = $config; + $this->genConfig = $gen_config; + $this->prepareGenerator($gen_config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns . '.' . $directive); + } + + $ret = ''; + $ret .= $this->start('table', array('class' => 'hp-config')); + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + foreach ($all as $ns => $directives) { + $ret .= $this->renderNamespace($ns, $directives); + } + if ($render_controls) { + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a single namespace + * @param $ns String namespace name + * @param array $directives array of directives to values + * @return string + */ + protected function renderNamespace($ns, $directives) + { + $ret = ''; + $ret .= $this->start('tbody', array('class' => 'namespace')); + $ret .= $this->start('tr'); + $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + foreach ($directives as $directive => $value) { + $ret .= $this->start('tr'); + $ret .= $this->start('th'); + if ($this->docURL) { + $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); + $ret .= $this->start('a', array('href' => $url)); + } + $attr = array('for' => "{$this->name}:$ns.$directive"); + + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } + + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) { + $ret .= $this->end('a'); + } + $ret .= $this->end('th'); + + $ret .= $this->start('td'); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) { + $type = 0; + } // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + } + $ret .= $this->end('tbody'); + return $ret; + } + +} + +/** + * Printer decorator for directives that accept null + */ +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer +{ + /** + * Printer being decorated + * @type HTMLPurifier_Printer + */ + protected $obj; + + /** + * @param HTMLPurifier_Printer $obj Printer to decorate + */ + public function __construct($obj) + { + parent::__construct(); + $this->obj = $obj; + } + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + + $ret = ''; + $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Null/Disabled'); + $ret .= $this->end('label'); + $attr = array( + 'type' => 'checkbox', + 'value' => '1', + 'class' => 'null-toggle', + 'name' => "$name" . "[Null_$ns.$directive]", + 'id' => "$name:Null_$ns.$directive", + 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! + ); + if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { + // modify inline javascript slightly + $attr['onclick'] = + "toggleWriteability('$name:Yes_$ns.$directive',checked);" . + "toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) { + $attr['checked'] = 'checked'; + } + $ret .= $this->elementEmpty('input', $attr); + $ret .= $this->text(' or '); + $ret .= $this->elementEmpty('br'); + $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); + return $ret; + } +} + +/** + * Swiss-army knife configuration form field printer + */ +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer +{ + /** + * @type int + */ + public $cols = 18; + + /** + * @type int + */ + public $rows = 5; + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + // this should probably be split up a little + $ret = ''; + $def = $config->def->info["$ns.$directive"]; + if (is_int($def)) { + $type = abs($def); + } else { + $type = $def->type; + } + if (is_array($value)) { + switch ($type) { + case HTMLPurifier_VarParser::LOOKUP: + $array = $value; + $value = array(); + foreach ($array as $val => $b) { + $value[] = $val; + } + //TODO does this need a break? + case HTMLPurifier_VarParser::ALIST: + $value = implode(PHP_EOL, $value); + break; + case HTMLPurifier_VarParser::HASH: + $nvalue = ''; + foreach ($value as $i => $v) { + if (is_array($v)) { + // HACK + $v = implode(";", $v); + } + $nvalue .= "$i:$v" . PHP_EOL; + } + $value = $nvalue; + break; + default: + $value = ''; + } + } + if ($type === HTMLPurifier_VarParser::C_MIXED) { + return 'Not supported'; + $value = serialize($value); + } + $attr = array( + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:$ns.$directive" + ); + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + if (isset($def->allowed)) { + $ret .= $this->start('select', $attr); + foreach ($def->allowed as $val => $b) { + $attr = array(); + if ($value == $val) { + $attr['selected'] = 'selected'; + } + $ret .= $this->element('option', $val, $attr); + } + $ret .= $this->end('select'); + } elseif ($type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP) { + $attr['cols'] = $this->cols; + $attr['rows'] = $this->rows; + $ret .= $this->start('textarea', $attr); + $ret .= $this->text($value); + $ret .= $this->end('textarea'); + } else { + $attr['value'] = $value; + $attr['type'] = 'text'; + $ret .= $this->elementEmpty('input', $attr); + } + return $ret; + } +} + +/** + * Bool form field printer + */ +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer +{ + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + $ret = ''; + $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); + + $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Yes'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:Yes_$ns.$directive", + 'value' => '1' + ); + if ($value === true) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' No'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:No_$ns.$directive", + 'value' => '0' + ); + if ($value === false) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php new file mode 100644 index 0000000000..ae8639176e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php @@ -0,0 +1,324 @@ +config =& $config; + + $this->def = $config->getHTMLDefinition(); + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + + $ret .= $this->renderDoctype(); + $ret .= $this->renderEnvironment(); + $ret .= $this->renderContentSets(); + $ret .= $this->renderInfo(); + + $ret .= $this->end('div'); + + return $ret; + } + + /** + * Renders the Doctype table + * @return string + */ + protected function renderDoctype() + { + $doctype = $this->def->doctype; + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Doctype'); + $ret .= $this->row('Name', $doctype->name); + $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); + $ret .= $this->row('Default Modules', implode(', ', $doctype->modules)); + $ret .= $this->row('Default Tidy Modules', implode(', ', $doctype->tidyModules)); + $ret .= $this->end('table'); + return $ret; + } + + + /** + * Renders environment table, which is miscellaneous info + * @return string + */ + protected function renderEnvironment() + { + $def = $this->def; + + $ret = ''; + + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Environment'); + + $ret .= $this->row('Parent of fragment', $def->info_parent); + $ret .= $this->renderChildren($def->info_parent_def->child); + $ret .= $this->row('Block wrap name', $def->info_block_wrapper); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->end('tr'); + + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Content Sets table + * @return string + */ + protected function renderContentSets() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Content Sets'); + foreach ($this->def->info_content_sets as $name => $lookup) { + $ret .= $this->heavyHeader($name); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($lookup)); + $ret .= $this->end('tr'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Elements ($info) table + * @return string + */ + protected function renderInfo() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Elements ($info)'); + ksort($this->def->info); + $ret .= $this->heavyHeader('Allowed tags', 2); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); + $ret .= $this->end('tr'); + foreach ($this->def->info as $name => $def) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->end('tr'); + if (!empty($def->excludes)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_pre)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_post)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->end('tr'); + } + if (!empty($def->auto_close)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->end('tr'); + } + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0); + $ret .= $this->end('tr'); + + if (!empty($def->required_attr)) { + $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); + } + + $ret .= $this->renderChildren($def->child); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a row describing the allowed children of an element + * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element + * @return string + */ + protected function renderChildren($def) + { + $context = new HTMLPurifier_Context(); + $ret = ''; + $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { + $elements = array(); + } elseif ($def->type == 'table') { + $elements = array_flip( + array( + 'col', + 'caption', + 'colgroup', + 'thead', + 'tfoot', + 'tbody', + 'tr' + ) + ); + } + $ret .= $this->element('th', 'Allowed children', $attr); + + if ($def->type == 'chameleon') { + + $ret .= $this->element( + 'td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)), + null, + 0 + ); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element( + 'td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)), + null, + 0 + ); + + } elseif ($def->type == 'custom') { + + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $def->dtd_regex + ); + + } else { + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $this->escape($this->listifyTagLookup($elements)), + null, + 0 + ); + } + $ret .= $this->end('tr'); + return $ret; + } + + /** + * Listifies a tag lookup table. + * @param array $array Tag lookup array in form of array('tagname' => true) + * @return string + */ + protected function listifyTagLookup($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $discard) { + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) { + continue; + } + $list[] = $name; + } + return $this->listify($list); + } + + /** + * Listifies a list of objects by retrieving class names and internal state + * @param array $array List of objects + * @return string + * @todo Also add information about internal state + */ + protected function listifyObjectList($array) + { + ksort($array); + $list = array(); + foreach ($array as $obj) { + $list[] = $this->getClass($obj, 'AttrTransform_'); + } + return $this->listify($list); + } + + /** + * Listifies a hash of attributes to AttrDef classes + * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @return string + */ + protected function listifyAttr($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $obj) { + if ($obj === false) { + continue; + } + $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; + } + return $this->listify($list); + } + + /** + * Creates a heavy header row + * @param string $text + * @param int $num + * @return string + */ + protected function heavyHeader($text, $num = 1) + { + $ret = ''; + $ret .= $this->start('tr'); + $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); + $ret .= $this->end('tr'); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php new file mode 100644 index 0000000000..189348fd9e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php @@ -0,0 +1,122 @@ +parent = $parent; + } + + /** + * Recursively retrieves the value for a key + * @param string $name + * @throws HTMLPurifier_Exception + */ + public function get($name) + { + if ($this->has($name)) { + return $this->data[$name]; + } + // possible performance bottleneck, convert to iterative if necessary + if ($this->parent) { + return $this->parent->get($name); + } + throw new HTMLPurifier_Exception("Key '$name' not found"); + } + + /** + * Sets the value of a key, for this plist + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * Returns true if a given key exists + * @param string $name + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->data); + } + + /** + * Resets a value to the value of it's parent, usually the default. If + * no value is specified, the entire plist is reset. + * @param string $name + */ + public function reset($name = null) + { + if ($name == null) { + $this->data = array(); + } else { + unset($this->data[$name]); + } + } + + /** + * Squashes this property list and all of its property lists into a single + * array, and returns the array. This value is cached by default. + * @param bool $force If true, ignores the cache and regenerates the array. + * @return array + */ + public function squash($force = false) + { + if ($this->cache !== null && !$force) { + return $this->cache; + } + if ($this->parent) { + return $this->cache = array_merge($this->parent->squash($force), $this->data); + } else { + return $this->cache = $this->data; + } + } + + /** + * Returns the parent plist. + * @return HTMLPurifier_PropertyList + */ + public function getParent() + { + return $this->parent; + } + + /** + * Sets the parent plist. + * @param HTMLPurifier_PropertyList $plist Parent plist + */ + public function setParent($plist) + { + $this->parent = $plist; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php new file mode 100644 index 0000000000..f68fc8c30f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php @@ -0,0 +1,43 @@ +l = strlen($filter); + $this->filter = $filter; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function accept() + { + $key = $this->getInnerIterator()->key(); + if (strncmp($key, $this->filter, $this->l) !== 0) { + return false; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php new file mode 100644 index 0000000000..f58db9042a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php @@ -0,0 +1,56 @@ +input = $input; + $this->output = array(); + } + + /** + * Shifts an element off the front of the queue. + */ + public function shift() { + if (empty($this->output)) { + $this->output = array_reverse($this->input); + $this->input = array(); + } + if (empty($this->output)) { + return NULL; + } + return array_pop($this->output); + } + + /** + * Pushes an element onto the front of the queue. + */ + public function push($x) { + array_push($this->input, $x); + } + + /** + * Checks if it's empty. + */ + public function isEmpty() { + return empty($this->input) && empty($this->output); + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php new file mode 100644 index 0000000000..e1ff3b72df --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php @@ -0,0 +1,26 @@ +strategies as $strategy) { + $tokens = $strategy->execute($tokens, $config, $context); + } + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php new file mode 100644 index 0000000000..4414c17d6e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php @@ -0,0 +1,17 @@ +strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); + $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 0000000000..6fa673db9a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,181 @@ +getHTMLDefinition(); + + $excludes_enabled = !$config->get('Core.DisableExcludes'); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array($definition->info_parent_def->excludes); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $node = $top_node; + // dummy token + list($token, $d) = $node->toTokenPair(); + $context->register('CurrentNode', $node); + $context->register('CurrentToken', $token); + + //####################################################################// + // Loop + + // We need to implement a post-order traversal iteratively, to + // avoid running into stack space limits. This is pretty tricky + // to reason about, so we just manually stack-ify the recursive + // variant: + // + // function f($node) { + // foreach ($node->children as $child) { + // f($child); + // } + // validate($node); + // } + // + // Thus, we will represent a stack frame as array($node, + // $is_inline, stack of children) + // e.g. array_reverse($node->children) - already processed + // children. + + $parent_def = $definition->info_parent_def; + $stack = array( + array($top_node, + $parent_def->descendants_are_inline, + $parent_def->excludes, // exclusions + 0) + ); + + while (!empty($stack)) { + list($node, $is_inline, $excludes, $ix) = array_pop($stack); + // recursive call + $go = false; + $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name]; + while (isset($node->children[$ix])) { + $child = $node->children[$ix++]; + if ($child instanceof HTMLPurifier_Node_Element) { + $go = true; + $stack[] = array($node, $is_inline, $excludes, $ix); + $stack[] = array($child, + // ToDo: I don't think it matters if it's def or + // child_def, but double check this... + $is_inline || $def->descendants_are_inline, + empty($def->excludes) ? $excludes + : array_merge($excludes, $def->excludes), + 0); + break; + } + }; + if ($go) continue; + list($token, $d) = $node->toTokenPair(); + // base case + if ($excludes_enabled && isset($excludes[$node->name])) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + // XXX I suppose it would be slightly more efficient to + // avoid the allocation here and have children + // strategies handle it + $children = array(); + foreach ($node->children as $child) { + if (!$child->dead) $children[] = $child; + } + $result = $def->child->validateChildren($children, $config, $context); + if ($result === true) { + // nop + $node->children = $children; + } elseif ($result === false) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } else { + $node->children = $result; + if ($e) { + // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators + if (empty($result) && !empty($children)) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else if ($result != $children) { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + } + } + } + + //####################################################################// + // Post-processing + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentNode'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return HTMLPurifier_Arborize::flatten($node, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php new file mode 100644 index 0000000000..a6eb09e453 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -0,0 +1,659 @@ +getHTMLDefinition(); + + // local variables + $generator = new HTMLPurifier_Generator($config, $context); + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + // used for autoclose early abortion + $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config); + $e = $context->get('ErrorCollector', true); + $i = false; // injector index + list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens); + if ($token === NULL) { + return array(); + } + $reprocess = false; // whether or not to reprocess the same token + $stack = array(); + + // member variables + $this->stack =& $stack; + $this->tokens =& $tokens; + $this->token =& $token; + $this->zipper =& $zipper; + $this->config = $config; + $this->context = $context; + + // context variables + $context->register('CurrentNesting', $stack); + $context->register('InputZipper', $zipper); + $context->register('CurrentToken', $token); + + // -- begin INJECTOR -- + + $this->injectors = array(); + + $injectors = $config->getBatch('AutoFormat'); + $def_injectors = $definition->info_injector; + $custom_injectors = $injectors['Custom']; + unset($injectors['Custom']); // special case + foreach ($injectors as $injector => $b) { + // XXX: Fix with a legitimate lookup table of enabled filters + if (strpos($injector, '.') !== false) { + continue; + } + $injector = "HTMLPurifier_Injector_$injector"; + if (!$b) { + continue; + } + $this->injectors[] = new $injector; + } + foreach ($def_injectors as $injector) { + // assumed to be objects + $this->injectors[] = $injector; + } + foreach ($custom_injectors as $injector) { + if (!$injector) { + continue; + } + if (is_string($injector)) { + $injector = "HTMLPurifier_Injector_$injector"; + $injector = new $injector; + } + $this->injectors[] = $injector; + } + + // give the injectors references to the definition and context + // variables for performance reasons + foreach ($this->injectors as $ix => $injector) { + $error = $injector->prepare($config, $context); + if (!$error) { + continue; + } + array_splice($this->injectors, $ix, 1); // rm the injector + trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); + } + + // -- end INJECTOR -- + + // a note on reprocessing: + // In order to reduce code duplication, whenever some code needs + // to make HTML changes in order to make things "correct", the + // new HTML gets sent through the purifier, regardless of its + // status. This means that if we add a start token, because it + // was totally necessary, we don't have to update nesting; we just + // punt ($reprocess = true; continue;) and it does that for us. + + // isset is in loop because $tokens size changes during loop exec + for (;; + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $token = $zipper->next($token)) { + + // check for a rewind + if (is_int($i)) { + // possibility: disable rewinding if the current token has a + // rewind set on it already. This would offer protection from + // infinite loop, but might hinder some advanced rewinding. + $rewind_offset = $this->injectors[$i]->getRewindOffset(); + if (is_int($rewind_offset)) { + for ($j = 0; $j < $rewind_offset; $j++) { + if (empty($zipper->front)) break; + $token = $zipper->prev($token); + // indicate that other injectors should not process this token, + // but we need to reprocess it. See Note [Injector skips] + unset($token->skip[$i]); + $token->rewind = $i; + if ($token instanceof HTMLPurifier_Token_Start) { + array_pop($this->stack); + } elseif ($token instanceof HTMLPurifier_Token_End) { + $this->stack[] = $token->start; + } + } + } + $i = false; + } + + // handle case of document end + if ($token === NULL) { + // kill processing if stack is empty + if (empty($this->stack)) { + break; + } + + // peek + $top_nesting = array_pop($this->stack); + $this->stack[] = $top_nesting; + + // send error [TagClosedSuppress] + if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); + } + + // append, don't splice, since this is the end + $token = new HTMLPurifier_Token_End($top_nesting->name); + + // punt! + $reprocess = true; + continue; + } + + //echo '
'; printZipper($zipper, $token);//printTokens($this->stack); + //flush(); + + // quick-check: if it's not a tag, no need to process + if (empty($token->is_tag)) { + if ($token instanceof HTMLPurifier_Token_Text) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + // See Note [Injector skips] + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + // XXX fuckup + $r = $token; + $injector->handleText($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + } + // another possibility is a comment + continue; + } + + if (isset($definition->info[$token->name])) { + $type = $definition->info[$token->name]->child->type; + } else { + $type = false; // Type is unknown, treat accordingly + } + + // quick tag checks: anything that's *not* an end tag + $ok = false; + if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { + // claims to be a start tag but is empty + $token = new HTMLPurifier_Token_Empty( + $token->name, + $token->attr, + $token->line, + $token->col, + $token->armor + ); + $ok = true; + } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { + // claims to be empty but really is a start tag + // NB: this assignment is required + $old_token = $token; + $token = new HTMLPurifier_Token_End($token->name); + $token = $this->insertBefore( + new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor) + ); + // punt (since we had to modify the input stream in a non-trivial way) + $reprocess = true; + continue; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // real empty token + $ok = true; + } elseif ($token instanceof HTMLPurifier_Token_Start) { + // start tag + + // ...unless they also have to close their parent + if (!empty($this->stack)) { + + // Performance note: you might think that it's rather + // inefficient, recalculating the autoclose information + // for every tag that a token closes (since when we + // do an autoclose, we push a new token into the + // stream and then /process/ that, before + // re-processing this token.) But this is + // necessary, because an injector can make an + // arbitrary transformations to the autoclosing + // tokens we introduce, so things may have changed + // in the meantime. Also, doing the inefficient thing is + // "easy" to reason about (for certain perverse definitions + // of "easy") + + $parent = array_pop($this->stack); + $this->stack[] = $parent; + + $parent_def = null; + $parent_elements = null; + $autoclose = false; + if (isset($definition->info[$parent->name])) { + $parent_def = $definition->info[$parent->name]; + $parent_elements = $parent_def->child->getAllowedElements($config); + $autoclose = !isset($parent_elements[$token->name]); + } + + if ($autoclose && $definition->info[$token->name]->wrap) { + // Check if an element can be wrapped by another + // element to make it valid in a context (for + // example,
      needs a
    • in between) + $wrapname = $definition->info[$token->name]->wrap; + $wrapdef = $definition->info[$wrapname]; + $elements = $wrapdef->child->getAllowedElements($config); + if (isset($elements[$token->name]) && isset($parent_elements[$wrapname])) { + $newtoken = new HTMLPurifier_Token_Start($wrapname); + $token = $this->insertBefore($newtoken); + $reprocess = true; + continue; + } + } + + $carryover = false; + if ($autoclose && $parent_def->formatting) { + $carryover = true; + } + + if ($autoclose) { + // check if this autoclose is doomed to fail + // (this rechecks $parent, which his harmless) + $autoclose_ok = isset($global_parent_allowed_elements[$token->name]); + if (!$autoclose_ok) { + foreach ($this->stack as $ancestor) { + $elements = $definition->info[$ancestor->name]->child->getAllowedElements($config); + if (isset($elements[$token->name])) { + $autoclose_ok = true; + break; + } + if ($definition->info[$token->name]->wrap) { + $wrapname = $definition->info[$token->name]->wrap; + $wrapdef = $definition->info[$wrapname]; + $wrap_elements = $wrapdef->child->getAllowedElements($config); + if (isset($wrap_elements[$token->name]) && isset($elements[$wrapname])) { + $autoclose_ok = true; + break; + } + } + } + } + if ($autoclose_ok) { + // errors need to be updated + $new_token = new HTMLPurifier_Token_End($parent->name); + $new_token->start = $parent; + // [TagClosedSuppress] + if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) { + if (!$carryover) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent); + } else { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent); + } + } + if ($carryover) { + $element = clone $parent; + // [TagClosedAuto] + $element->armor['MakeWellFormed_TagClosedError'] = true; + $element->carryover = true; + $token = $this->processToken(array($new_token, $token, $element)); + } else { + $token = $this->insertBefore($new_token); + } + } else { + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + } + $ok = true; + } + + if ($ok) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + // See Note [Injector skips] + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + $r = $token; + $injector->handleElement($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + if (!$reprocess) { + // ah, nothing interesting happened; do normal processing + if ($token instanceof HTMLPurifier_Token_Start) { + $this->stack[] = $token; + } elseif ($token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception( + 'Improper handling of end tag in start code; possible error in MakeWellFormed' + ); + } + } + continue; + } + + // sanity check: we should be dealing with a closing tag + if (!$token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception('Unaccounted for tag token in input stream, bug in HTML Purifier'); + } + + // make sure that we have something open + if (empty($this->stack)) { + if ($escape_invalid_tags) { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); + } + $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token)); + } else { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); + } + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + // first, check for the simplest case: everything closes neatly. + // Eventually, everything passes through here; if there are problems + // we modify the input stream accordingly and then punt, so that + // the tokens get processed again. + $current_parent = array_pop($this->stack); + if ($current_parent->name == $token->name) { + $token->start = $current_parent; + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + // See Note [Injector skips] + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + $r = $token; + $injector->handleEnd($r); + $token = $this->processToken($r, $i); + $this->stack[] = $current_parent; + $reprocess = true; + break; + } + continue; + } + + // okay, so we're trying to close the wrong tag + + // undo the pop previous pop + $this->stack[] = $current_parent; + + // scroll back the entire nest, trying to find our tag. + // (feature could be to specify how far you'd like to go) + $size = count($this->stack); + // -2 because -1 is the last element, but we already checked that + $skipped_tags = false; + for ($j = $size - 2; $j >= 0; $j--) { + if ($this->stack[$j]->name == $token->name) { + $skipped_tags = array_slice($this->stack, $j); + break; + } + } + + // we didn't find the tag, so remove + if ($skipped_tags === false) { + if ($escape_invalid_tags) { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); + } + $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token)); + } else { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); + } + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + // do errors, in REVERSE $j order: a,b,c with + $c = count($skipped_tags); + if ($e) { + for ($j = $c - 1; $j > 0; $j--) { + // notice we exclude $j == 0, i.e. the current ending tag, from + // the errors... [TagClosedSuppress] + if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]); + } + } + } + + // insert tags, in FORWARD $j order: c,b,a with + $replace = array($token); + for ($j = 1; $j < $c; $j++) { + // ...as well as from the insertions + $new_token = new HTMLPurifier_Token_End($skipped_tags[$j]->name); + $new_token->start = $skipped_tags[$j]; + array_unshift($replace, $new_token); + if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) { + // [TagClosedAuto] + $element = clone $skipped_tags[$j]; + $element->carryover = true; + $element->armor['MakeWellFormed_TagClosedError'] = true; + $replace[] = $element; + } + } + $token = $this->processToken($replace); + $reprocess = true; + continue; + } + + $context->destroy('CurrentToken'); + $context->destroy('CurrentNesting'); + $context->destroy('InputZipper'); + + unset($this->injectors, $this->stack, $this->tokens); + return $zipper->toArray($token); + } + + /** + * Processes arbitrary token values for complicated substitution patterns. + * In general: + * + * If $token is an array, it is a list of tokens to substitute for the + * current token. These tokens then get individually processed. If there + * is a leading integer in the list, that integer determines how many + * tokens from the stream should be removed. + * + * If $token is a regular token, it is swapped with the current token. + * + * If $token is false, the current token is deleted. + * + * If $token is an integer, that number of tokens (with the first token + * being the current one) will be deleted. + * + * @param HTMLPurifier_Token|array|int|bool $token Token substitution value + * @param HTMLPurifier_Injector|int $injector Injector that performed the substitution; default is if + * this is not an injector related operation. + * @throws HTMLPurifier_Exception + */ + protected function processToken($token, $injector = -1) + { + // Zend OpCache miscompiles $token = array($token), so + // avoid this pattern. See: https://github.com/ezyang/htmlpurifier/issues/108 + + // normalize forms of token + if (is_object($token)) { + $tmp = $token; + $token = array(1, $tmp); + } + if (is_int($token)) { + $tmp = $token; + $token = array($tmp); + } + if ($token === false) { + $token = array(1); + } + if (!is_array($token)) { + throw new HTMLPurifier_Exception('Invalid token type from injector'); + } + if (!is_int($token[0])) { + array_unshift($token, 1); + } + if ($token[0] === 0) { + throw new HTMLPurifier_Exception('Deleting zero tokens is not valid'); + } + + // $token is now an array with the following form: + // array(number nodes to delete, new node 1, new node 2, ...) + + $delete = array_shift($token); + list($old, $r) = $this->zipper->splice($this->token, $delete, $token); + + if ($injector > -1) { + // See Note [Injector skips] + // Determine appropriate skips. Here's what the code does: + // *If* we deleted one or more tokens, copy the skips + // of those tokens into the skips of the new tokens (in $token). + // Also, mark the newly inserted tokens as having come from + // $injector. + $oldskip = isset($old[0]) ? $old[0]->skip : array(); + foreach ($token as $object) { + $object->skip = $oldskip; + $object->skip[$injector] = true; + } + } + + return $r; + + } + + /** + * Inserts a token before the current token. Cursor now points to + * this token. You must reprocess after this. + * @param HTMLPurifier_Token $token + */ + private function insertBefore($token) + { + // NB not $this->zipper->insertBefore(), due to positioning + // differences + $splice = $this->zipper->splice($this->token, 0, array($token)); + + return $splice[1]; + } + + /** + * Removes current token. Cursor now points to new token occupying previously + * occupied space. You must reprocess after this. + */ + private function remove() + { + return $this->zipper->delete(); + } +} + +// Note [Injector skips] +// ~~~~~~~~~~~~~~~~~~~~~ +// When I originally designed this class, the idea behind the 'skip' +// property of HTMLPurifier_Token was to help avoid infinite loops +// in injector processing. For example, suppose you wrote an injector +// that bolded swear words. Naively, you might write it so that +// whenever you saw ****, you replaced it with ****. +// +// When this happens, we will reprocess all of the tokens with the +// other injectors. Now there is an opportunity for infinite loop: +// if we rerun the swear-word injector on these tokens, we might +// see **** and then reprocess again to get +// **** ad infinitum. +// +// Thus, the idea of a skip is that once we process a token with +// an injector, we mark all of those tokens as having "come from" +// the injector, and we never run the injector again on these +// tokens. +// +// There were two more complications, however: +// +// - With HTMLPurifier_Injector_RemoveEmpty, we noticed that if +// you had , after you removed the , you +// really would like this injector to go back and reprocess +// the tag, discovering that it is now empty and can be +// removed. So we reintroduced the possibility of infinite looping +// by adding a "rewind" function, which let you go back to an +// earlier point in the token stream and reprocess it with injectors. +// Needless to say, we need to UN-skip the token so it gets +// reprocessed. +// +// - Suppose that you successfuly process a token, replace it with +// one with your skip mark, but now another injector wants to +// process the skipped token with another token. Should you continue +// to skip that new token, or reprocess it? If you reprocess, +// you can end up with an infinite loop where one injector converts +// to , and then another injector converts it back. So +// we inherit the skips, but for some reason, I thought that we +// should inherit the skip from the first token of the token +// that we deleted. Why? Well, it seems to work OK. +// +// If I were to redesign this functionality, I would absolutely not +// go about doing it this way: the semantics are just not very well +// defined, and in any case you probably wanted to operate on trees, +// not token streams. + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php new file mode 100644 index 0000000000..1a8149eccb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php @@ -0,0 +1,207 @@ +getHTMLDefinition(); + $generator = new HTMLPurifier_Generator($config, $context); + $result = array(); + + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + $remove_invalid_img = $config->get('Core.RemoveInvalidImg'); + + // currently only used to determine if comments should be kept + $trusted = $config->get('HTML.Trusted'); + $comment_lookup = $config->get('HTML.AllowedComments'); + $comment_regexp = $config->get('HTML.AllowedCommentsRegexp'); + $check_comments = $comment_lookup !== array() || $comment_regexp !== null; + + $remove_script_contents = $config->get('Core.RemoveScriptContents'); + $hidden_elements = $config->get('Core.HiddenElements'); + + // remove script contents compatibility + if ($remove_script_contents === true) { + $hidden_elements['script'] = true; + } elseif ($remove_script_contents === false && isset($hidden_elements['script'])) { + unset($hidden_elements['script']); + } + + $attr_validator = new HTMLPurifier_AttrValidator(); + + // removes tokens until it reaches a closing tag with its value + $remove_until = false; + + // converts comments into text tokens when this is equal to a tag name + $textify_comments = false; + + $token = false; + $context->register('CurrentToken', $token); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + foreach ($tokens as $token) { + if ($remove_until) { + if (empty($token->is_tag) || $token->name !== $remove_until) { + continue; + } + } + if (!empty($token->is_tag)) { + // DEFINITION CALL + + // before any processing, try to transform the element + if (isset($definition->info_tag_transform[$token->name])) { + $original_name = $token->name; + // there is a transformation for this tag + // DEFINITION CALL + $token = $definition-> + info_tag_transform[$token->name]->transform($token, $config, $context); + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name); + } + } + + if (isset($definition->info[$token->name])) { + // mostly everything's good, but + // we need to make sure required attributes are in order + if (($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) && + $definition->info[$token->name]->required_attr && + ($token->name != 'img' || $remove_invalid_img) // ensure config option still works + ) { + $attr_validator->validateToken($token, $config, $context); + $ok = true; + foreach ($definition->info[$token->name]->required_attr as $name) { + if (!isset($token->attr[$name])) { + $ok = false; + break; + } + } + if (!$ok) { + if ($e) { + $e->send( + E_ERROR, + 'Strategy_RemoveForeignElements: Missing required attribute', + $name + ); + } + continue; + } + $token->armor['ValidateAttributes'] = true; + } + + if (isset($hidden_elements[$token->name]) && $token instanceof HTMLPurifier_Token_Start) { + $textify_comments = $token->name; + } elseif ($token->name === $textify_comments && $token instanceof HTMLPurifier_Token_End) { + $textify_comments = false; + } + + } elseif ($escape_invalid_tags) { + // invalid tag, generate HTML representation and insert in + if ($e) { + $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); + } + $token = new HTMLPurifier_Token_Text( + $generator->generateFromToken($token) + ); + } else { + // check if we need to destroy all of the tag's children + // CAN BE GENERICIZED + if (isset($hidden_elements[$token->name])) { + if ($token instanceof HTMLPurifier_Token_Start) { + $remove_until = $token->name; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // do nothing: we're still looking + } else { + $remove_until = false; + } + if ($e) { + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'); + } + } else { + if ($e) { + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); + } + } + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + // textify comments in script tags when they are allowed + if ($textify_comments !== false) { + $data = $token->data; + $token = new HTMLPurifier_Token_Text($data); + } elseif ($trusted || $check_comments) { + // always cleanup comments + $trailing_hyphen = false; + if ($e) { + // perform check whether or not there's a trailing hyphen + if (substr($token->data, -1) == '-') { + $trailing_hyphen = true; + } + } + $token->data = rtrim($token->data, '-'); + $found_double_hyphen = false; + while (strpos($token->data, '--') !== false) { + $found_double_hyphen = true; + $token->data = str_replace('--', '-', $token->data); + } + if ($trusted || !empty($comment_lookup[trim($token->data)]) || + ($comment_regexp !== null && preg_match($comment_regexp, trim($token->data)))) { + // OK good + if ($e) { + if ($trailing_hyphen) { + $e->send( + E_NOTICE, + 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' + ); + } + if ($found_double_hyphen) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); + } + } + } else { + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + } + continue; + } + } else { + // strip comments + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + } + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Text) { + } else { + continue; + } + $result[] = $token; + } + if ($remove_until && $e) { + // we removed tokens until the end, throw error + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until); + } + $context->destroy('CurrentToken'); + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php new file mode 100644 index 0000000000..fbb3d27c81 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php @@ -0,0 +1,45 @@ +register('CurrentToken', $token); + + foreach ($tokens as $key => $token) { + + // only process tokens that have attributes, + // namely start and empty tags + if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) { + continue; + } + + // skip tokens that are armored + if (!empty($token->armor['ValidateAttributes'])) { + continue; + } + + // note that we have no facilities here for removing tokens + $validator->validateToken($token, $config, $context); + } + $context->destroy('CurrentToken'); + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php new file mode 100644 index 0000000000..c41ae3a76d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php @@ -0,0 +1,48 @@ +accessed[$index] = true; + return parent::offsetGet($index); + } + + /** + * Returns a lookup array of all array indexes that have been accessed. + * @return array in form array($index => true). + */ + public function getAccessed() + { + return $this->accessed; + } + + /** + * Resets the access array. + */ + public function resetAccessed() + { + $this->accessed = array(); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php new file mode 100644 index 0000000000..7c73f80835 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php @@ -0,0 +1,136 @@ + 'DefaultKeyValue', + * 'KEY' => 'Value', + * 'KEY2' => 'Value2', + * 'MULTILINE-KEY' => "Multiline\nvalue.\n", + * ) + * + * We use this as an easy to use file-format for configuration schema + * files, but the class itself is usage agnostic. + * + * You can use ---- to forcibly terminate parsing of a single string-hash; + * this marker is used in multi string-hashes to delimit boundaries. + */ +class HTMLPurifier_StringHashParser +{ + + /** + * @type string + */ + public $default = 'ID'; + + /** + * Parses a file that contains a single string-hash. + * @param string $file + * @return array + */ + public function parseFile($file) + { + if (!file_exists($file)) { + return false; + } + $fh = fopen($file, 'r'); + if (!$fh) { + return false; + } + $ret = $this->parseHandle($fh); + fclose($fh); + return $ret; + } + + /** + * Parses a file that contains multiple string-hashes delimited by '----' + * @param string $file + * @return array + */ + public function parseMultiFile($file) + { + if (!file_exists($file)) { + return false; + } + $ret = array(); + $fh = fopen($file, 'r'); + if (!$fh) { + return false; + } + while (!feof($fh)) { + $ret[] = $this->parseHandle($fh); + } + fclose($fh); + return $ret; + } + + /** + * Internal parser that acepts a file handle. + * @note While it's possible to simulate in-memory parsing by using + * custom stream wrappers, if such a use-case arises we should + * factor out the file handle into its own class. + * @param resource $fh File handle with pointer at start of valid string-hash + * block. + * @return array + */ + protected function parseHandle($fh) + { + $state = false; + $single = false; + $ret = array(); + do { + $line = fgets($fh); + if ($line === false) { + break; + } + $line = rtrim($line, "\n\r"); + if (!$state && $line === '') { + continue; + } + if ($line === '----') { + break; + } + if (strncmp('--#', $line, 3) === 0) { + // Comment + continue; + } elseif (strncmp('--', $line, 2) === 0) { + // Multiline declaration + $state = trim($line, '- '); + if (!isset($ret[$state])) { + $ret[$state] = ''; + } + continue; + } elseif (!$state) { + $single = true; + if (strpos($line, ':') !== false) { + // Single-line declaration + list($state, $line) = explode(':', $line, 2); + $line = trim($line); + } else { + // Use default declaration + $state = $this->default; + } + } + if ($single) { + $ret[$state] = $line; + $single = false; + $state = false; + } else { + $ret[$state] .= "$line\n"; + } + } while (!feof($fh)); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php new file mode 100644 index 0000000000..7b8d833433 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php @@ -0,0 +1,37 @@ + '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%' + ); + + /** + * @param HTMLPurifier_Token_Tag $tag + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token_End|string + */ + public function transform($tag, $config, $context) + { + if ($tag instanceof HTMLPurifier_Token_End) { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + return $new_tag; + } + + $attr = $tag->attr; + $prepend_style = ''; + + // handle color transform + if (isset($attr['color'])) { + $prepend_style .= 'color:' . $attr['color'] . ';'; + unset($attr['color']); + } + + // handle face transform + if (isset($attr['face'])) { + $prepend_style .= 'font-family:' . $attr['face'] . ';'; + unset($attr['face']); + } + + // handle size transform + if (isset($attr['size'])) { + // normalize large numbers + if ($attr['size'] !== '') { + if ($attr['size'][0] == '+' || $attr['size'][0] == '-') { + $size = (int)$attr['size']; + if ($size < -2) { + $attr['size'] = '-2'; + } + if ($size > 4) { + $attr['size'] = '+4'; + } + } else { + $size = (int)$attr['size']; + if ($size > 7) { + $attr['size'] = '7'; + } + } + } + if (isset($this->_size_lookup[$attr['size']])) { + $prepend_style .= 'font-size:' . + $this->_size_lookup[$attr['size']] . ';'; + } + unset($attr['size']); + } + + if ($prepend_style) { + $attr['style'] = isset($attr['style']) ? + $prepend_style . $attr['style'] : + $prepend_style; + } + + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + $new_tag->attr = $attr; + + return $new_tag; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php new file mode 100644 index 0000000000..71bf10b91f --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php @@ -0,0 +1,44 @@ +transform_to = $transform_to; + $this->style = $style; + } + + /** + * @param HTMLPurifier_Token_Tag $tag + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function transform($tag, $config, $context) + { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + if (!is_null($this->style) && + ($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty) + ) { + $this->prependCSS($new_tag->attr, $this->style); + } + return $new_tag; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token.php new file mode 100644 index 0000000000..84d3619a36 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token.php @@ -0,0 +1,100 @@ +line = $l; + $this->col = $c; + } + + /** + * Convenience function for DirectLex settings line/col position. + * @param int $l + * @param int $c + */ + public function rawPosition($l, $c) + { + if ($c === -1) { + $l++; + } + $this->line = $l; + $this->col = $c; + } + + /** + * Converts a token into its corresponding node. + */ + abstract public function toNode(); +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php new file mode 100644 index 0000000000..23453c7052 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php @@ -0,0 +1,38 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toNode() { + return new HTMLPurifier_Node_Comment($this->data, $this->line, $this->col); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php new file mode 100644 index 0000000000..78a95f5555 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php @@ -0,0 +1,15 @@ +empty = true; + return $n; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php new file mode 100644 index 0000000000..59b38fdc57 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php @@ -0,0 +1,24 @@ +toNode not supported!"); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php new file mode 100644 index 0000000000..019f317ada --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php @@ -0,0 +1,10 @@ +!empty($obj->is_tag) + * without having to use a function call is_a(). + * @type bool + */ + public $is_tag = true; + + /** + * The lower-case name of the tag, like 'a', 'b' or 'blockquote'. + * + * @note Strictly speaking, XML tags are case sensitive, so we shouldn't + * be lower-casing them, but these tokens cater to HTML tags, which are + * insensitive. + * @type string + */ + public $name; + + /** + * Associative array of the tag's attributes. + * @type array + */ + public $attr = array(); + + /** + * Non-overloaded constructor, which lower-cases passed tag name. + * + * @param string $name String name. + * @param array $attr Associative array of attributes. + * @param int $line + * @param int $col + * @param array $armor + */ + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) + { + $this->name = ctype_lower($name) ? $name : strtolower($name); + foreach ($attr as $key => $value) { + // normalization only necessary when key is not lowercase + if (!ctype_lower((string)$key)) { + $new_key = strtolower($key); + if (!isset($attr[$new_key])) { + $attr[$new_key] = $attr[$key]; + } + if ($new_key !== $key) { + unset($attr[$key]); + } + } + } + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toNode() { + return new HTMLPurifier_Node_Element($this->name, $this->attr, $this->line, $this->col, $this->armor); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php new file mode 100644 index 0000000000..f26a1c211b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php @@ -0,0 +1,53 @@ +data = $data; + $this->is_whitespace = ctype_space($data); + $this->line = $line; + $this->col = $col; + } + + public function toNode() { + return new HTMLPurifier_Node_Text($this->data, $this->is_whitespace, $this->line, $this->col); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php new file mode 100644 index 0000000000..dea2446b93 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php @@ -0,0 +1,118 @@ +p_start = new HTMLPurifier_Token_Start('', array()); + $this->p_end = new HTMLPurifier_Token_End(''); + $this->p_empty = new HTMLPurifier_Token_Empty('', array()); + $this->p_text = new HTMLPurifier_Token_Text(''); + $this->p_comment = new HTMLPurifier_Token_Comment(''); + } + + /** + * Creates a HTMLPurifier_Token_Start. + * @param string $name Tag name + * @param array $attr Associative array of attributes + * @return HTMLPurifier_Token_Start Generated HTMLPurifier_Token_Start + */ + public function createStart($name, $attr = array()) + { + $p = clone $this->p_start; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_End. + * @param string $name Tag name + * @return HTMLPurifier_Token_End Generated HTMLPurifier_Token_End + */ + public function createEnd($name) + { + $p = clone $this->p_end; + $p->__construct($name); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Empty. + * @param string $name Tag name + * @param array $attr Associative array of attributes + * @return HTMLPurifier_Token_Empty Generated HTMLPurifier_Token_Empty + */ + public function createEmpty($name, $attr = array()) + { + $p = clone $this->p_empty; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Text. + * @param string $data Data of text token + * @return HTMLPurifier_Token_Text Generated HTMLPurifier_Token_Text + */ + public function createText($data) + { + $p = clone $this->p_text; + $p->__construct($data); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Comment. + * @param string $data Data of comment token + * @return HTMLPurifier_Token_Comment Generated HTMLPurifier_Token_Comment + */ + public function createComment($data) + { + $p = clone $this->p_comment; + $p->__construct($data); + return $p; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URI.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URI.php new file mode 100644 index 0000000000..9c5be39d18 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URI.php @@ -0,0 +1,316 @@ +scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); + $this->userinfo = $userinfo; + $this->host = $host; + $this->port = is_null($port) ? $port : (int)$port; + $this->path = $path; + $this->query = $query; + $this->fragment = $fragment; + } + + /** + * Retrieves a scheme object corresponding to the URI's scheme/default + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_URIScheme Scheme object appropriate for validating this URI + */ + public function getSchemeObj($config, $context) + { + $registry = HTMLPurifier_URISchemeRegistry::instance(); + if ($this->scheme !== null) { + $scheme_obj = $registry->getScheme($this->scheme, $config, $context); + if (!$scheme_obj) { + return false; + } // invalid scheme, clean it out + } else { + // no scheme: retrieve the default one + $def = $config->getDefinition('URI'); + $scheme_obj = $def->getDefaultScheme($config, $context); + if (!$scheme_obj) { + if ($def->defaultScheme !== null) { + // something funky happened to the default scheme object + trigger_error( + 'Default scheme object "' . $def->defaultScheme . '" was not readable', + E_USER_WARNING + ); + } // suppress error if it's null + return false; + } + } + return $scheme_obj; + } + + /** + * Generic validation method applicable for all schemes. May modify + * this URI in order to get it into a compliant form. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool True if validation/filtering succeeds, false if failure + */ + public function validate($config, $context) + { + // ABNF definitions from RFC 3986 + $chars_sub_delims = '!$&\'()*+,;='; + $chars_gen_delims = ':/?#[]@'; + $chars_pchar = $chars_sub_delims . ':@'; + + // validate host + if (!is_null($this->host)) { + $host_def = new HTMLPurifier_AttrDef_URI_Host(); + $this->host = $host_def->validate($this->host, $config, $context); + if ($this->host === false) { + $this->host = null; + } + } + + // validate scheme + // NOTE: It's not appropriate to check whether or not this + // scheme is in our registry, since a URIFilter may convert a + // URI that we don't allow into one we do. So instead, we just + // check if the scheme can be dropped because there is no host + // and it is our default scheme. + if (!is_null($this->scheme) && is_null($this->host) || $this->host === '') { + // support for relative paths is pretty abysmal when the + // scheme is present, so axe it when possible + $def = $config->getDefinition('URI'); + if ($def->defaultScheme === $this->scheme) { + $this->scheme = null; + } + } + + // validate username + if (!is_null($this->userinfo)) { + $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); + $this->userinfo = $encoder->encode($this->userinfo); + } + + // validate port + if (!is_null($this->port)) { + if ($this->port < 1 || $this->port > 65535) { + $this->port = null; + } + } + + // validate path + $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); + if (!is_null($this->host)) { // this catches $this->host === '' + // path-abempty (hier and relative) + // http://www.example.com/my/path + // //www.example.com/my/path (looks odd, but works, and + // recognized by most browsers) + // (this set is valid or invalid on a scheme by scheme + // basis, so we'll deal with it later) + // file:///my/path + // ///my/path + $this->path = $segments_encoder->encode($this->path); + } elseif ($this->path !== '') { + if ($this->path[0] === '/') { + // path-absolute (hier and relative) + // http:/my/path + // /my/path + if (strlen($this->path) >= 2 && $this->path[1] === '/') { + // This could happen if both the host gets stripped + // out + // http://my/path + // //my/path + $this->path = ''; + } else { + $this->path = $segments_encoder->encode($this->path); + } + } elseif (!is_null($this->scheme)) { + // path-rootless (hier) + // http:my/path + // Short circuit evaluation means we don't need to check nz + $this->path = $segments_encoder->encode($this->path); + } else { + // path-noscheme (relative) + // my/path + // (once again, not checking nz) + $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); + $c = strpos($this->path, '/'); + if ($c !== false) { + $this->path = + $segment_nc_encoder->encode(substr($this->path, 0, $c)) . + $segments_encoder->encode(substr($this->path, $c)); + } else { + $this->path = $segment_nc_encoder->encode($this->path); + } + } + } else { + // path-empty (hier and relative) + $this->path = ''; // just to be safe + } + + // qf = query and fragment + $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); + + if (!is_null($this->query)) { + $this->query = $qf_encoder->encode($this->query); + } + + if (!is_null($this->fragment)) { + $this->fragment = $qf_encoder->encode($this->fragment); + } + return true; + } + + /** + * Convert URI back to string + * @return string URI appropriate for output + */ + public function toString() + { + // reconstruct authority + $authority = null; + // there is a rendering difference between a null authority + // (http:foo-bar) and an empty string authority + // (http:///foo-bar). + if (!is_null($this->host)) { + $authority = ''; + if (!is_null($this->userinfo)) { + $authority .= $this->userinfo . '@'; + } + $authority .= $this->host; + if (!is_null($this->port)) { + $authority .= ':' . $this->port; + } + } + + // Reconstruct the result + // One might wonder about parsing quirks from browsers after + // this reconstruction. Unfortunately, parsing behavior depends + // on what *scheme* was employed (file:///foo is handled *very* + // differently than http:///foo), so unfortunately we have to + // defer to the schemes to do the right thing. + $result = ''; + if (!is_null($this->scheme)) { + $result .= $this->scheme . ':'; + } + if (!is_null($authority)) { + $result .= '//' . $authority; + } + $result .= $this->path; + if (!is_null($this->query)) { + $result .= '?' . $this->query; + } + if (!is_null($this->fragment)) { + $result .= '#' . $this->fragment; + } + + return $result; + } + + /** + * Returns true if this URL might be considered a 'local' URL given + * the current context. This is true when the host is null, or + * when it matches the host supplied to the configuration. + * + * Note that this does not do any scheme checking, so it is mostly + * only appropriate for metadata that doesn't care about protocol + * security. isBenign is probably what you actually want. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function isLocal($config, $context) + { + if ($this->host === null) { + return true; + } + $uri_def = $config->getDefinition('URI'); + if ($uri_def->host === $this->host) { + return true; + } + return false; + } + + /** + * Returns true if this URL should be considered a 'benign' URL, + * that is: + * + * - It is a local URL (isLocal), and + * - It has a equal or better level of security + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function isBenign($config, $context) + { + if (!$this->isLocal($config, $context)) { + return false; + } + + $scheme_obj = $this->getSchemeObj($config, $context); + if (!$scheme_obj) { + return false; + } // conservative approach + + $current_scheme_obj = $config->getDefinition('URI')->getDefaultScheme($config, $context); + if ($current_scheme_obj->secure) { + if (!$scheme_obj->secure) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php new file mode 100644 index 0000000000..e0bd8bcca8 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php @@ -0,0 +1,112 @@ +registerFilter(new HTMLPurifier_URIFilter_DisableExternal()); + $this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources()); + $this->registerFilter(new HTMLPurifier_URIFilter_DisableResources()); + $this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist()); + $this->registerFilter(new HTMLPurifier_URIFilter_SafeIframe()); + $this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute()); + $this->registerFilter(new HTMLPurifier_URIFilter_Munge()); + } + + public function registerFilter($filter) + { + $this->registeredFilters[$filter->name] = $filter; + } + + public function addFilter($filter, $config) + { + $r = $filter->prepare($config); + if ($r === false) return; // null is ok, for backwards compat + if ($filter->post) { + $this->postFilters[$filter->name] = $filter; + } else { + $this->filters[$filter->name] = $filter; + } + } + + protected function doSetup($config) + { + $this->setupMemberVariables($config); + $this->setupFilters($config); + } + + protected function setupFilters($config) + { + foreach ($this->registeredFilters as $name => $filter) { + if ($filter->always_load) { + $this->addFilter($filter, $config); + } else { + $conf = $config->get('URI.' . $name); + if ($conf !== false && $conf !== null) { + $this->addFilter($filter, $config); + } + } + } + unset($this->registeredFilters); + } + + protected function setupMemberVariables($config) + { + $this->host = $config->get('URI.Host'); + $base_uri = $config->get('URI.Base'); + if (!is_null($base_uri)) { + $parser = new HTMLPurifier_URIParser(); + $this->base = $parser->parse($base_uri); + $this->defaultScheme = $this->base->scheme; + if (is_null($this->host)) $this->host = $this->base->host; + } + if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme'); + } + + public function getDefaultScheme($config, $context) + { + return HTMLPurifier_URISchemeRegistry::instance()->getScheme($this->defaultScheme, $config, $context); + } + + public function filter(&$uri, $config, $context) + { + foreach ($this->filters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + + public function postFilter(&$uri, $config, $context) + { + foreach ($this->postFilters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php new file mode 100644 index 0000000000..09724e9f41 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php @@ -0,0 +1,74 @@ +getDefinition('URI')->host; + if ($our_host !== null) { + $this->ourHostParts = array_reverse(explode('.', $our_host)); + } + } + + /** + * @param HTMLPurifier_URI $uri Reference + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if (is_null($uri->host)) { + return true; + } + if ($this->ourHostParts === false) { + return false; + } + $host_parts = array_reverse(explode('.', $uri->host)); + foreach ($this->ourHostParts as $i => $x) { + if (!isset($host_parts[$i])) { + return false; + } + if ($host_parts[$i] != $this->ourHostParts[$i]) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php new file mode 100644 index 0000000000..c6562169e0 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php @@ -0,0 +1,25 @@ +get('EmbeddedURI', true)) { + return true; + } + return parent::filter($uri, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php new file mode 100644 index 0000000000..d5c412c444 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php @@ -0,0 +1,22 @@ +get('EmbeddedURI', true); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php new file mode 100644 index 0000000000..32197c0e61 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php @@ -0,0 +1,46 @@ +blacklist = $config->get('URI.HostBlacklist'); + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + foreach ($this->blacklist as $blacklisted_host_fragment) { + if ($uri->host !== null && strpos($uri->host, $blacklisted_host_fragment) !== false) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php new file mode 100644 index 0000000000..c507bbff8e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php @@ -0,0 +1,158 @@ +getDefinition('URI'); + $this->base = $def->base; + if (is_null($this->base)) { + trigger_error( + 'URI.MakeAbsolute is being ignored due to lack of ' . + 'value for URI.Base configuration', + E_USER_WARNING + ); + return false; + } + $this->base->fragment = null; // fragment is invalid for base URI + $stack = explode('/', $this->base->path); + array_pop($stack); // discard last segment + $stack = $this->_collapseStack($stack); // do pre-parsing + $this->basePathStack = $stack; + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if (is_null($this->base)) { + return true; + } // abort early + if ($uri->path === '' && is_null($uri->scheme) && + is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment)) { + // reference to current document + $uri = clone $this->base; + return true; + } + if (!is_null($uri->scheme)) { + // absolute URI already: don't change + if (!is_null($uri->host)) { + return true; + } + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + // scheme not recognized + return false; + } + if (!$scheme_obj->hierarchical) { + // non-hierarchal URI with explicit scheme, don't change + return true; + } + // special case: had a scheme but always is hierarchical and had no authority + } + if (!is_null($uri->host)) { + // network path, don't bother + return true; + } + if ($uri->path === '') { + $uri->path = $this->base->path; + } elseif ($uri->path[0] !== '/') { + // relative path, needs more complicated processing + $stack = explode('/', $uri->path); + $new_stack = array_merge($this->basePathStack, $stack); + if ($new_stack[0] !== '' && !is_null($this->base->host)) { + array_unshift($new_stack, ''); + } + $new_stack = $this->_collapseStack($new_stack); + $uri->path = implode('/', $new_stack); + } else { + // absolute path, but still we should collapse + $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); + } + // re-combine + $uri->scheme = $this->base->scheme; + if (is_null($uri->userinfo)) { + $uri->userinfo = $this->base->userinfo; + } + if (is_null($uri->host)) { + $uri->host = $this->base->host; + } + if (is_null($uri->port)) { + $uri->port = $this->base->port; + } + return true; + } + + /** + * Resolve dots and double-dots in a path stack + * @param array $stack + * @return array + */ + private function _collapseStack($stack) + { + $result = array(); + $is_folder = false; + for ($i = 0; isset($stack[$i]); $i++) { + $is_folder = false; + // absorb an internally duplicated slash + if ($stack[$i] == '' && $i && isset($stack[$i + 1])) { + continue; + } + if ($stack[$i] == '..') { + if (!empty($result)) { + $segment = array_pop($result); + if ($segment === '' && empty($result)) { + // error case: attempted to back out too far: + // restore the leading slash + $result[] = ''; + } elseif ($segment === '..') { + $result[] = '..'; // cannot remove .. with .. + } + } else { + // relative path, preserve the double-dots + $result[] = '..'; + } + $is_folder = true; + continue; + } + if ($stack[$i] == '.') { + // silently absorb + $is_folder = true; + continue; + } + $result[] = $stack[$i]; + } + if ($is_folder) { + $result[] = ''; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php new file mode 100644 index 0000000000..e1393deb73 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php @@ -0,0 +1,115 @@ +target = $config->get('URI.' . $this->name); + $this->parser = new HTMLPurifier_URIParser(); + $this->doEmbed = $config->get('URI.MungeResources'); + $this->secretKey = $config->get('URI.MungeSecretKey'); + if ($this->secretKey && !function_exists('hash_hmac')) { + throw new Exception("Cannot use %URI.MungeSecretKey without hash_hmac support."); + } + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if ($context->get('EmbeddedURI', true) && !$this->doEmbed) { + return true; + } + + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + return true; + } // ignore unknown schemes, maybe another postfilter did it + if (!$scheme_obj->browsable) { + return true; + } // ignore non-browseable schemes, since we can't munge those in a reasonable way + if ($uri->isBenign($config, $context)) { + return true; + } // don't redirect if a benign URL + + $this->makeReplace($uri, $config, $context); + $this->replace = array_map('rawurlencode', $this->replace); + + $new_uri = strtr($this->target, $this->replace); + $new_uri = $this->parser->parse($new_uri); + // don't redirect if the target host is the same as the + // starting host + if ($uri->host === $new_uri->host) { + return true; + } + $uri = $new_uri; // overwrite + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + protected function makeReplace($uri, $config, $context) + { + $string = $uri->toString(); + // always available + $this->replace['%s'] = $string; + $this->replace['%r'] = $context->get('EmbeddedURI', true) ?: ''; + $token = $context->get('CurrentToken', true) ?: ''; + $this->replace['%n'] = $token ? $token->name : ''; + $this->replace['%m'] = $context->get('CurrentAttr', true) ?: ''; + $this->replace['%p'] = $context->get('CurrentCSSProperty', true) ?: ''; + // not always available + if ($this->secretKey) { + $this->replace['%t'] = hash_hmac("sha256", $string, $this->secretKey); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php new file mode 100644 index 0000000000..f609c47a34 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php @@ -0,0 +1,68 @@ +regexp = $config->get('URI.SafeIframeRegexp'); + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + // check if filter not applicable + if (!$config->get('HTML.SafeIframe')) { + return true; + } + // check if the filter should actually trigger + if (!$context->get('EmbeddedURI', true)) { + return true; + } + $token = $context->get('CurrentToken', true); + if (!($token && $token->name == 'iframe')) { + return true; + } + // check if we actually have some whitelists enabled + if ($this->regexp === null) { + return false; + } + // actually check the whitelists + return preg_match($this->regexp, $uri->toString()); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php new file mode 100644 index 0000000000..0e7381a07b --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php @@ -0,0 +1,71 @@ +percentEncoder = new HTMLPurifier_PercentEncoder(); + } + + /** + * Parses a URI. + * @param $uri string URI to parse + * @return HTMLPurifier_URI representation of URI. This representation has + * not been validated yet and may not conform to RFC. + */ + public function parse($uri) + { + $uri = $this->percentEncoder->normalize($uri); + + // Regexp is as per Appendix B. + // Note that ["<>] are an addition to the RFC's recommended + // characters, because they represent external delimeters. + $r_URI = '!'. + '(([a-zA-Z0-9\.\+\-]+):)?'. // 2. Scheme + '(//([^/?#"<>]*))?'. // 4. Authority + '([^?#"<>]*)'. // 5. Path + '(\?([^#"<>]*))?'. // 7. Query + '(#([^"<>]*))?'. // 8. Fragment + '!'; + + $matches = array(); + $result = preg_match($r_URI, $uri, $matches); + + if (!$result) return false; // *really* invalid URI + + // seperate out parts + $scheme = !empty($matches[1]) ? $matches[2] : null; + $authority = !empty($matches[3]) ? $matches[4] : null; + $path = $matches[5]; // always present, can be empty + $query = !empty($matches[6]) ? $matches[7] : null; + $fragment = !empty($matches[8]) ? $matches[9] : null; + + // further parse authority + if ($authority !== null) { + $r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/"; + $matches = array(); + preg_match($r_authority, $authority, $matches); + $userinfo = !empty($matches[1]) ? $matches[2] : null; + $host = !empty($matches[3]) ? $matches[3] : ''; + $port = !empty($matches[4]) ? (int) $matches[5] : null; + } else { + $port = $host = $userinfo = null; + } + + return new HTMLPurifier_URI( + $scheme, $userinfo, $host, $port, $path, $query, $fragment); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php new file mode 100644 index 0000000000..fe9e82cf26 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php @@ -0,0 +1,102 @@ +, resolves edge cases + * with making relative URIs absolute + * @type bool + */ + public $hierarchical = false; + + /** + * Whether or not the URI may omit a hostname when the scheme is + * explicitly specified, ala file:///path/to/file. As of writing, + * 'file' is the only scheme that browsers support his properly. + * @type bool + */ + public $may_omit_host = false; + + /** + * Validates the components of a URI for a specific scheme. + * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool success or failure + */ + abstract public function doValidate(&$uri, $config, $context); + + /** + * Public interface for validating components of a URI. Performs a + * bunch of default actions. Don't overload this method. + * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool success or failure + */ + public function validate(&$uri, $config, $context) + { + if ($this->default_port == $uri->port) { + $uri->port = null; + } + // kludge: browsers do funny things when the scheme but not the + // authority is set + if (!$this->may_omit_host && + // if the scheme is present, a missing host is always in error + (!is_null($uri->scheme) && ($uri->host === '' || is_null($uri->host))) || + // if the scheme is not present, a *blank* host is in error, + // since this translates into '///path' which most browsers + // interpret as being 'http://path'. + (is_null($uri->scheme) && $uri->host === '') + ) { + do { + if (is_null($uri->scheme)) { + if (substr($uri->path, 0, 2) != '//') { + $uri->host = null; + break; + } + // URI is '////path', so we cannot nullify the + // host to preserve semantics. Try expanding the + // hostname instead (fall through) + } + // first see if we can manually insert a hostname + $host = $config->get('URI.Host'); + if (!is_null($host)) { + $uri->host = $host; + } else { + // we can't do anything sensible, reject the URL. + return false; + } + } while (false); + } + return $this->doValidate($uri, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php new file mode 100644 index 0000000000..41c49d5533 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php @@ -0,0 +1,136 @@ + true, + 'image/gif' => true, + 'image/png' => true, + ); + // this is actually irrelevant since we only write out the path + // component + /** + * @type bool + */ + public $may_omit_host = true; + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function doValidate(&$uri, $config, $context) + { + $result = explode(',', $uri->path, 2); + $is_base64 = false; + $charset = null; + $content_type = null; + if (count($result) == 2) { + list($metadata, $data) = $result; + // do some legwork on the metadata + $metas = explode(';', $metadata); + while (!empty($metas)) { + $cur = array_shift($metas); + if ($cur == 'base64') { + $is_base64 = true; + break; + } + if (substr($cur, 0, 8) == 'charset=') { + // doesn't match if there are arbitrary spaces, but + // whatever dude + if ($charset !== null) { + continue; + } // garbage + $charset = substr($cur, 8); // not used + } else { + if ($content_type !== null) { + continue; + } // garbage + $content_type = $cur; + } + } + } else { + $data = $result[0]; + } + if ($content_type !== null && empty($this->allowed_types[$content_type])) { + return false; + } + if ($charset !== null) { + // error; we don't allow plaintext stuff + $charset = null; + } + $data = rawurldecode($data); + if ($is_base64) { + $raw_data = base64_decode($data); + } else { + $raw_data = $data; + } + if ( strlen($raw_data) < 12 ) { + // error; exif_imagetype throws exception with small files, + // and this likely indicates a corrupt URI/failed parse anyway + return false; + } + // XXX probably want to refactor this into a general mechanism + // for filtering arbitrary content types + if (function_exists('sys_get_temp_dir')) { + $file = tempnam(sys_get_temp_dir(), ""); + } else { + $file = tempnam("/tmp", ""); + } + file_put_contents($file, $raw_data); + if (function_exists('exif_imagetype')) { + $image_code = exif_imagetype($file); + unlink($file); + } elseif (function_exists('getimagesize')) { + set_error_handler(array($this, 'muteErrorHandler')); + $info = getimagesize($file); + restore_error_handler(); + unlink($file); + if ($info == false) { + return false; + } + $image_code = $info[2]; + } else { + trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR); + } + $real_content_type = image_type_to_mime_type($image_code); + if ($real_content_type != $content_type) { + // we're nice guys; if the content type is something else we + // support, change it over + if (empty($this->allowed_types[$real_content_type])) { + return false; + } + $content_type = $real_content_type; + } + // ok, it's kosher, rewrite what we need + $uri->userinfo = null; + $uri->host = null; + $uri->port = null; + $uri->fragment = null; + $uri->query = null; + $uri->path = "$content_type;base64," . base64_encode($raw_data); + return true; + } + + /** + * @param int $errno + * @param string $errstr + */ + public function muteErrorHandler($errno, $errstr) + { + } +} diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php new file mode 100644 index 0000000000..215be4ba80 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php @@ -0,0 +1,44 @@ +userinfo = null; + // file:// makes no provisions for accessing the resource + $uri->port = null; + // While it seems to work on Firefox, the querystring has + // no possible effect and is thus stripped. + $uri->query = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php new file mode 100644 index 0000000000..1eb43ee5c4 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php @@ -0,0 +1,58 @@ +query = null; + + // typecode check + $semicolon_pos = strrpos($uri->path, ';'); // reverse + if ($semicolon_pos !== false) { + $type = substr($uri->path, $semicolon_pos + 1); // no semicolon + $uri->path = substr($uri->path, 0, $semicolon_pos); + $type_ret = ''; + if (strpos($type, '=') !== false) { + // figure out whether or not the declaration is correct + list($key, $typecode) = explode('=', $type, 2); + if ($key !== 'type') { + // invalid key, tack it back on encoded + $uri->path .= '%3B' . $type; + } elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') { + $type_ret = ";type=$typecode"; + } + } else { + $uri->path .= '%3B' . $type; + } + $uri->path = str_replace(';', '%3B', $uri->path); + $uri->path .= $type_ret; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php new file mode 100644 index 0000000000..ce69ec438a --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php @@ -0,0 +1,36 @@ +userinfo = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php new file mode 100644 index 0000000000..0e96882db9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php @@ -0,0 +1,18 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + // we need to validate path against RFC 2368's addr-spec + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php new file mode 100644 index 0000000000..7490927d63 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php @@ -0,0 +1,35 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + $uri->query = null; + // typecode check needed on path + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php new file mode 100644 index 0000000000..f211d715e9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php @@ -0,0 +1,32 @@ +userinfo = null; + $uri->query = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/tel.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/tel.php new file mode 100644 index 0000000000..dfad8efcf9 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/tel.php @@ -0,0 +1,46 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + + // Delete all non-numeric characters, commas, and non-x characters + // from phone number, EXCEPT for a leading plus sign. + $uri->path = preg_replace('/(?!^\+)[^\dx,]/', '', + // Normalize e(x)tension to lower-case + str_replace('X', 'x', rawurldecode($uri->path))); + + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php new file mode 100644 index 0000000000..4ac8a0b76e --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php @@ -0,0 +1,81 @@ +get('URI.AllowedSchemes'); + if (!$config->get('URI.OverrideAllowedSchemes') && + !isset($allowed_schemes[$scheme]) + ) { + return; + } + + if (isset($this->schemes[$scheme])) { + return $this->schemes[$scheme]; + } + if (!isset($allowed_schemes[$scheme])) { + return; + } + + $class = 'HTMLPurifier_URIScheme_' . $scheme; + if (!class_exists($class)) { + return; + } + $this->schemes[$scheme] = new $class(); + return $this->schemes[$scheme]; + } + + /** + * Registers a custom scheme to the cache, bypassing reflection. + * @param string $scheme Scheme name + * @param HTMLPurifier_URIScheme $scheme_obj + */ + public function register($scheme, $scheme_obj) + { + $this->schemes[$scheme] = $scheme_obj; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php new file mode 100644 index 0000000000..b5a1eab5ca --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php @@ -0,0 +1,307 @@ + array( + 'px' => 3, // This is as per CSS 2.1 and Firefox. Your mileage may vary + 'pt' => 4, + 'pc' => 48, + 'in' => 288, + self::METRIC => array('pt', '0.352777778', 'mm'), + ), + self::METRIC => array( + 'mm' => 1, + 'cm' => 10, + self::ENGLISH => array('mm', '2.83464567', 'pt'), + ), + ); + + /** + * Minimum bcmath precision for output. + * @type int + */ + protected $outputPrecision; + + /** + * Bcmath precision for internal calculations. + * @type int + */ + protected $internalPrecision; + + /** + * Whether or not BCMath is available. + * @type bool + */ + private $bcmath; + + public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) + { + $this->outputPrecision = $output_precision; + $this->internalPrecision = $internal_precision; + $this->bcmath = !$force_no_bcmath && function_exists('bcmul'); + } + + /** + * Converts a length object of one unit into another unit. + * @param HTMLPurifier_Length $length + * Instance of HTMLPurifier_Length to convert. You must validate() + * it before passing it here! + * @param string $to_unit + * Unit to convert to. + * @return HTMLPurifier_Length|bool + * @note + * About precision: This conversion function pays very special + * attention to the incoming precision of values and attempts + * to maintain a number of significant figure. Results are + * fairly accurate up to nine digits. Some caveats: + * - If a number is zero-padded as a result of this significant + * figure tracking, the zeroes will be eliminated. + * - If a number contains less than four sigfigs ($outputPrecision) + * and this causes some decimals to be excluded, those + * decimals will be added on. + */ + public function convert($length, $to_unit) + { + if (!$length->isValid()) { + return false; + } + + $n = $length->getN(); + $unit = $length->getUnit(); + + if ($n === '0' || $unit === false) { + return new HTMLPurifier_Length('0', false); + } + + $state = $dest_state = false; + foreach (self::$units as $k => $x) { + if (isset($x[$unit])) { + $state = $k; + } + if (isset($x[$to_unit])) { + $dest_state = $k; + } + } + if (!$state || !$dest_state) { + return false; + } + + // Some calculations about the initial precision of the number; + // this will be useful when we need to do final rounding. + $sigfigs = $this->getSigFigs($n); + if ($sigfigs < $this->outputPrecision) { + $sigfigs = $this->outputPrecision; + } + + // BCMath's internal precision deals only with decimals. Use + // our default if the initial number has no decimals, or increase + // it by how ever many decimals, thus, the number of guard digits + // will always be greater than or equal to internalPrecision. + $log = (int)floor(log(abs($n), 10)); + $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision + + for ($i = 0; $i < 2; $i++) { + + // Determine what unit IN THIS SYSTEM we need to convert to + if ($dest_state === $state) { + // Simple conversion + $dest_unit = $to_unit; + } else { + // Convert to the smallest unit, pending a system shift + $dest_unit = self::$units[$state][$dest_state][0]; + } + + // Do the conversion if necessary + if ($dest_unit !== $unit) { + $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp); + $n = $this->mul($n, $factor, $cp); + $unit = $dest_unit; + } + + // Output was zero, so bail out early. Shouldn't ever happen. + if ($n === '') { + $n = '0'; + $unit = $to_unit; + break; + } + + // It was a simple conversion, so bail out + if ($dest_state === $state) { + break; + } + + if ($i !== 0) { + // Conversion failed! Apparently, the system we forwarded + // to didn't have this unit. This should never happen! + return false; + } + + // Pre-condition: $i == 0 + + // Perform conversion to next system of units + $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp); + $unit = self::$units[$state][$dest_state][2]; + $state = $dest_state; + + // One more loop around to convert the unit in the new system. + + } + + // Post-condition: $unit == $to_unit + if ($unit !== $to_unit) { + return false; + } + + // Useful for debugging: + //echo "
      n";
      +        //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n
      \n"; + + $n = $this->round($n, $sigfigs); + if (strpos($n, '.') !== false) { + $n = rtrim($n, '0'); + } + $n = rtrim($n, '.'); + + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Returns the number of significant figures in a string number. + * @param string $n Decimal number + * @return int number of sigfigs + */ + public function getSigFigs($n) + { + $n = ltrim($n, '0+-'); + $dp = strpos($n, '.'); // decimal position + if ($dp === false) { + $sigfigs = strlen(rtrim($n, '0')); + } else { + $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character + if ($dp !== 0) { + $sigfigs--; + } + } + return $sigfigs; + } + + /** + * Adds two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function add($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcadd($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 + (float)$s2, $scale); + } + } + + /** + * Multiples two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function mul($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcmul($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 * (float)$s2, $scale); + } + } + + /** + * Divides two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function div($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcdiv($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 / (float)$s2, $scale); + } + } + + /** + * Rounds a number according to the number of sigfigs it should have, + * using arbitrary precision when available. + * @param float $n + * @param int $sigfigs + * @return string + */ + private function round($n, $sigfigs) + { + $new_log = (int)floor(log(abs((float)$n), 10)); // Number of digits left of decimal - 1 + $rp = $sigfigs - $new_log - 1; // Number of decimal places needed + $neg = $n < 0 ? '-' : ''; // Negative sign + if ($this->bcmath) { + if ($rp >= 0) { + $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); + $n = bcdiv($n, '1', $rp); + } else { + // This algorithm partially depends on the standardized + // form of numbers that comes out of bcmath. + $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); + $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); + } + return $n; + } else { + return $this->scale(round((float)$n, $sigfigs - $new_log - 1), $rp + 1); + } + } + + /** + * Scales a float to $scale digits right of decimal point, like BCMath. + * @param float $r + * @param int $scale + * @return string + */ + private function scale($r, $scale) + { + if ($scale < 0) { + // The f sprintf type doesn't support negative numbers, so we + // need to cludge things manually. First get the string. + $r = sprintf('%.0f', (float)$r); + // Due to floating point precision loss, $r will more than likely + // look something like 4652999999999.9234. We grab one more digit + // than we need to precise from $r and then use that to round + // appropriately. + $precise = (string)round(substr($r, 0, strlen($r) + $scale), -1); + // Now we return it, truncating the zero that was rounded off. + return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); + } + return number_format((float)$r, $scale, '.', ''); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php new file mode 100644 index 0000000000..0c97c8289d --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php @@ -0,0 +1,198 @@ + self::C_STRING, + 'istring' => self::ISTRING, + 'text' => self::TEXT, + 'itext' => self::ITEXT, + 'int' => self::C_INT, + 'float' => self::C_FLOAT, + 'bool' => self::C_BOOL, + 'lookup' => self::LOOKUP, + 'list' => self::ALIST, + 'hash' => self::HASH, + 'mixed' => self::C_MIXED + ); + + /** + * Lookup table of types that are string, and can have aliases or + * allowed value lists. + */ + public static $stringTypes = array( + self::C_STRING => true, + self::ISTRING => true, + self::TEXT => true, + self::ITEXT => true, + ); + + /** + * Validate a variable according to type. + * It may return NULL as a valid type if $allow_null is true. + * + * @param mixed $var Variable to validate + * @param int $type Type of variable, see HTMLPurifier_VarParser->types + * @param bool $allow_null Whether or not to permit null as a value + * @return string Validated and type-coerced variable + * @throws HTMLPurifier_VarParserException + */ + final public function parse($var, $type, $allow_null = false) + { + if (is_string($type)) { + if (!isset(HTMLPurifier_VarParser::$types[$type])) { + throw new HTMLPurifier_VarParserException("Invalid type '$type'"); + } else { + $type = HTMLPurifier_VarParser::$types[$type]; + } + } + $var = $this->parseImplementation($var, $type, $allow_null); + if ($allow_null && $var === null) { + return null; + } + // These are basic checks, to make sure nothing horribly wrong + // happened in our implementations. + switch ($type) { + case (self::C_STRING): + case (self::ISTRING): + case (self::TEXT): + case (self::ITEXT): + if (!is_string($var)) { + break; + } + if ($type == self::ISTRING || $type == self::ITEXT) { + $var = strtolower($var); + } + return $var; + case (self::C_INT): + if (!is_int($var)) { + break; + } + return $var; + case (self::C_FLOAT): + if (!is_float($var)) { + break; + } + return $var; + case (self::C_BOOL): + if (!is_bool($var)) { + break; + } + return $var; + case (self::LOOKUP): + case (self::ALIST): + case (self::HASH): + if (!is_array($var)) { + break; + } + if ($type === self::LOOKUP) { + foreach ($var as $k) { + if ($k !== true) { + $this->error('Lookup table contains value other than true'); + } + } + } elseif ($type === self::ALIST) { + $keys = array_keys($var); + if (array_keys($keys) !== $keys) { + $this->error('Indices for list are not uniform'); + } + } + return $var; + case (self::C_MIXED): + return $var; + default: + $this->errorInconsistent(get_class($this), $type); + } + $this->errorGeneric($var, $type); + } + + /** + * Actually implements the parsing. Base implementation does not + * do anything to $var. Subclasses should overload this! + * @param mixed $var + * @param int $type + * @param bool $allow_null + * @return string + */ + protected function parseImplementation($var, $type, $allow_null) + { + return $var; + } + + /** + * Throws an exception. + * @throws HTMLPurifier_VarParserException + */ + protected function error($msg) + { + throw new HTMLPurifier_VarParserException($msg); + } + + /** + * Throws an inconsistency exception. + * @note This should not ever be called. It would be called if we + * extend the allowed values of HTMLPurifier_VarParser without + * updating subclasses. + * @param string $class + * @param int $type + * @throws HTMLPurifier_Exception + */ + protected function errorInconsistent($class, $type) + { + throw new HTMLPurifier_Exception( + "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) . + " not implemented" + ); + } + + /** + * Generic error for if a type didn't work. + * @param mixed $var + * @param int $type + */ + protected function errorGeneric($var, $type) + { + $vtype = gettype($var); + $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype"); + } + + /** + * @param int $type + * @return string + */ + public static function getTypeName($type) + { + static $lookup; + if (!$lookup) { + // Lazy load the alternative lookup table + $lookup = array_flip(HTMLPurifier_VarParser::$types); + } + if (!isset($lookup[$type])) { + return 'unknown'; + } + return $lookup[$type]; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php new file mode 100644 index 0000000000..3bfbe83868 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php @@ -0,0 +1,130 @@ + $j) { + $var[$i] = trim($j); + } + if ($type === self::HASH) { + // key:value,key2:value2 + $nvar = array(); + foreach ($var as $keypair) { + $c = explode(':', $keypair, 2); + if (!isset($c[1])) { + continue; + } + $nvar[trim($c[0])] = trim($c[1]); + } + $var = $nvar; + } + } + if (!is_array($var)) { + break; + } + $keys = array_keys($var); + if ($keys === array_keys($keys)) { + if ($type == self::ALIST) { + return $var; + } elseif ($type == self::LOOKUP) { + $new = array(); + foreach ($var as $key) { + $new[$key] = true; + } + return $new; + } else { + break; + } + } + if ($type === self::ALIST) { + trigger_error("Array list did not have consecutive integer indexes", E_USER_WARNING); + return array_values($var); + } + if ($type === self::LOOKUP) { + foreach ($var as $key => $value) { + if ($value !== true) { + trigger_error( + "Lookup array has non-true value at key '$key'; " . + "maybe your input array was not indexed numerically", + E_USER_WARNING + ); + } + $var[$key] = true; + } + } + return $var; + default: + $this->errorInconsistent(__CLASS__, $type); + } + $this->errorGeneric($var, $type); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php new file mode 100644 index 0000000000..f11c318efb --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php @@ -0,0 +1,38 @@ +evalExpression($var); + } + + /** + * @param string $expr + * @return mixed + * @throws HTMLPurifier_VarParserException + */ + protected function evalExpression($expr) + { + $var = null; + $result = eval("\$var = $expr;"); + if ($result === false) { + throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); + } + return $var; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php new file mode 100644 index 0000000000..5df3414959 --- /dev/null +++ b/lib/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php @@ -0,0 +1,11 @@ +front = $front; + $this->back = $back; + } + + /** + * Creates a zipper from an array, with a hole in the + * 0-index position. + * @param Array to zipper-ify. + * @return Tuple of zipper and element of first position. + */ + static public function fromArray($array) { + $z = new self(array(), array_reverse($array)); + $t = $z->delete(); // delete the "dummy hole" + return array($z, $t); + } + + /** + * Convert zipper back into a normal array, optionally filling in + * the hole with a value. (Usually you should supply a $t, unless you + * are at the end of the array.) + */ + public function toArray($t = NULL) { + $a = $this->front; + if ($t !== NULL) $a[] = $t; + for ($i = count($this->back)-1; $i >= 0; $i--) { + $a[] = $this->back[$i]; + } + return $a; + } + + /** + * Move hole to the next element. + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function next($t) { + if ($t !== NULL) array_push($this->front, $t); + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Iterated hole advancement. + * @param $t Element to fill hole with + * @param $i How many forward to advance hole + * @return Original contents of new hole, i away + */ + public function advance($t, $n) { + for ($i = 0; $i < $n; $i++) { + $t = $this->next($t); + } + return $t; + } + + /** + * Move hole to the previous element + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function prev($t) { + if ($t !== NULL) array_push($this->back, $t); + return empty($this->front) ? NULL : array_pop($this->front); + } + + /** + * Delete contents of current hole, shifting hole to + * next element. + * @return Original contents of new hole. + */ + public function delete() { + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Returns true if we are at the end of the list. + * @return bool + */ + public function done() { + return empty($this->back); + } + + /** + * Insert element before hole. + * @param Element to insert + */ + public function insertBefore($t) { + if ($t !== NULL) array_push($this->front, $t); + } + + /** + * Insert element after hole. + * @param Element to insert + */ + public function insertAfter($t) { + if ($t !== NULL) array_push($this->back, $t); + } + + /** + * Splice in multiple elements at hole. Functional specification + * in terms of array_splice: + * + * $arr1 = $arr; + * $old1 = array_splice($arr1, $i, $delete, $replacement); + * + * list($z, $t) = HTMLPurifier_Zipper::fromArray($arr); + * $t = $z->advance($t, $i); + * list($old2, $t) = $z->splice($t, $delete, $replacement); + * $arr2 = $z->toArray($t); + * + * assert($old1 === $old2); + * assert($arr1 === $arr2); + * + * NB: the absolute index location after this operation is + * *unchanged!* + * + * @param Current contents of hole. + */ + public function splice($t, $delete, $replacement) { + // delete + $old = array(); + $r = $t; + for ($i = $delete; $i > 0; $i--) { + $old[] = $r; + $r = $this->delete(); + } + // insert + for ($i = count($replacement)-1; $i >= 0; $i--) { + $this->insertAfter($r); + $r = $replacement[$i]; + } + return array($old, $r); + } +} diff --git a/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiff.php b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiff.php new file mode 100644 index 0000000000..74f0002173 --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiff.php @@ -0,0 +1,574 @@ +copy->insert + * command (swap) for when the inserted segment is exactly the same + * as the deleted one, and with only a copy operation in between. + * TODO: How often this case occurs? Is it worth it? Can only + * be done as a postprocessing method (->optimize()?) + */ + +/** + * FineDiff class + * + * TODO: Document + * + */ +class FineDiff { + + /**------------------------------------------------------------------------ + * + * Public section + * + */ + + /** + * Constructor + * ... + * The $granularityStack allows FineDiff to be configurable so that + * a particular stack tailored to the specific content of a document can + * be passed. + */ + public function __construct($from_text = '', $to_text = '', $granularityStack = null) { + // setup stack for generic text documents by default + $this->granularityStack = $granularityStack ? $granularityStack : FineDiff::$characterGranularity; + $this->edits = array(); + $this->from_text = $from_text; + $this->doDiff($from_text, $to_text); + } + + public function getOps() { + return $this->edits; + } + + public function getOpcodes() { + $opcodes = array(); + foreach ( $this->edits as $edit ) { + $opcodes[] = $edit->getOpcode(); + } + return implode('', $opcodes); + } + + public function renderDiffToHTML() { + $in_offset = 0; + ob_start(); + foreach ( $this->edits as $edit ) { + $n = $edit->getFromLen(); + if ( $edit instanceof FineDiffCopyOp ) { + FineDiff::renderDiffToHTMLFromOpcode('c', $this->from_text, $in_offset, $n); + } + else if ( $edit instanceof FineDiffDeleteOp ) { + FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n); + } + else if ( $edit instanceof FineDiffInsertOp ) { + FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen()); + } + else /* if ( $edit instanceof FineDiffReplaceOp ) */ { + FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n); + FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen()); + } + $in_offset += $n; + } + return ob_get_clean(); + } + + /**------------------------------------------------------------------------ + * Return an opcodes string describing the diff between a "From" and a + * "To" string + */ + public static function getDiffOpcodes($from, $to, $granularities = null) { + $diff = new FineDiff($from, $to, $granularities); + return $diff->getOpcodes(); + } + + /**------------------------------------------------------------------------ + * Return an iterable collection of diff ops from an opcodes string + */ + public static function getDiffOpsFromOpcodes($opcodes) { + $diffops = new FineDiffOps(); + FineDiff::renderFromOpcodes(null, $opcodes, array($diffops,'appendOpcode')); + return $diffops->edits; + } + + /**------------------------------------------------------------------------ + * Re-create the "To" string from the "From" string and an "Opcodes" string + */ + public static function renderToTextFromOpcodes($from, $opcodes) { + ob_start(); + FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderToTextFromOpcode')); + return ob_get_clean(); + } + + /**------------------------------------------------------------------------ + * Render the diff to an HTML string + */ + public static function renderDiffToHTMLFromOpcodes($from, $opcodes) { + ob_start(); + FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderDiffToHTMLFromOpcode')); + return ob_get_clean(); + } + + /**------------------------------------------------------------------------ + * Generic opcodes parser, user must supply callback for handling + * single opcode + */ + public static function renderFromOpcodes($from, $opcodes, $callback) { + if ( !is_callable($callback) ) { + return; + } + $opcodes_len = strlen($opcodes); + $from_offset = $opcodes_offset = 0; + while ( $opcodes_offset < $opcodes_len ) { + $opcode = substr($opcodes, $opcodes_offset, 1); + $opcodes_offset++; + $n = intval(substr($opcodes, $opcodes_offset)); + if ( $n ) { + $opcodes_offset += strlen(strval($n)); + } + else { + $n = 1; + } + if ( $opcode === 'c' ) { // copy n characters from source + call_user_func($callback, 'c', $from, $from_offset, $n, ''); + $from_offset += $n; + } + else if ( $opcode === 'd' ) { // delete n characters from source + call_user_func($callback, 'd', $from, $from_offset, $n, ''); + $from_offset += $n; + } + else /* if ( $opcode === 'i' ) */ { // insert n characters from opcodes + call_user_func($callback, 'i', $opcodes, $opcodes_offset + 1, $n); + $opcodes_offset += 1 + $n; + } + } + } + + /** + * Stock granularity stacks and delimiters + */ + + const paragraphDelimiters = "\n\r"; + public static $paragraphGranularity = array( + FineDiff::paragraphDelimiters + ); + const sentenceDelimiters = ".\n\r"; + public static $sentenceGranularity = array( + FineDiff::paragraphDelimiters, + FineDiff::sentenceDelimiters + ); + const wordDelimiters = " \t.\n\r"; + public static $wordGranularity = array( + FineDiff::paragraphDelimiters, + FineDiff::sentenceDelimiters, + FineDiff::wordDelimiters + ); + const characterDelimiters = ""; + public static $characterGranularity = array( + FineDiff::paragraphDelimiters, + FineDiff::sentenceDelimiters, + FineDiff::wordDelimiters, + FineDiff::characterDelimiters + ); + + public static $textStack = array( + ".", + " \t.\n\r", + "" + ); + + /**------------------------------------------------------------------------ + * + * Private section + * + */ + + /** + * Entry point to compute the diff. + */ + private function doDiff($from_text, $to_text) { + $this->last_edit = false; + $this->stackpointer = 0; + $this->from_text = $from_text; + $this->from_offset = 0; + // can't diff without at least one granularity specifier + if ( empty($this->granularityStack) ) { + return; + } + $this->_processGranularity($from_text, $to_text); + } + + /** + * This is the recursive function which is responsible for + * handling/increasing granularity. + * + * Incrementally increasing the granularity is key to compute the + * overall diff in a very efficient way. + */ + private function _processGranularity($from_segment, $to_segment) { + $delimiters = $this->granularityStack[$this->stackpointer++]; + $has_next_stage = $this->stackpointer < count($this->granularityStack); + foreach ( FineDiff::doFragmentDiff($from_segment, $to_segment, $delimiters) as $fragment_edit ) { + // increase granularity + if ( $fragment_edit instanceof FineDiffReplaceOp && $has_next_stage ) { + $this->_processGranularity( + substr($this->from_text, $this->from_offset, $fragment_edit->getFromLen()), + $fragment_edit->getText() + ); + } + // fuse copy ops whenever possible + else if ( $fragment_edit instanceof FineDiffCopyOp && $this->last_edit instanceof FineDiffCopyOp ) { + $this->edits[count($this->edits)-1]->increase($fragment_edit->getFromLen()); + $this->from_offset += $fragment_edit->getFromLen(); + } + else { + /* $fragment_edit instanceof FineDiffCopyOp */ + /* $fragment_edit instanceof FineDiffDeleteOp */ + /* $fragment_edit instanceof FineDiffInsertOp */ + $this->edits[] = $this->last_edit = $fragment_edit; + $this->from_offset += $fragment_edit->getFromLen(); + } + } + $this->stackpointer--; + } + + /** + * This is the core algorithm which actually perform the diff itself, + * fragmenting the strings as per specified delimiters. + * + * This function is naturally recursive, however for performance purpose + * a local job queue is used instead of outright recursivity. + */ + private static function doFragmentDiff($from_text, $to_text, $delimiters) { + // Empty delimiter means character-level diffing. + // In such case, use code path optimized for character-level + // diffing. + if ( empty($delimiters) ) { + return FineDiff::doCharDiff($from_text, $to_text); + } + + $result = array(); + + // fragment-level diffing + $from_text_len = strlen($from_text); + $to_text_len = strlen($to_text); + $from_fragments = FineDiff::extractFragments($from_text, $delimiters); + $to_fragments = FineDiff::extractFragments($to_text, $delimiters); + + $jobs = array(array(0, $from_text_len, 0, $to_text_len)); + + $cached_array_keys = array(); + + while ( $job = array_pop($jobs) ) { + + // get the segments which must be diff'ed + list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job; + + // catch easy cases first + $from_segment_length = $from_segment_end - $from_segment_start; + $to_segment_length = $to_segment_end - $to_segment_start; + if ( !$from_segment_length || !$to_segment_length ) { + if ( $from_segment_length ) { + $result[$from_segment_start * 4] = new FineDiffDeleteOp($from_segment_length); + } + else if ( $to_segment_length ) { + $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_length)); + } + continue; + } + + // find longest copy operation for the current segments + $best_copy_length = 0; + + $from_base_fragment_index = $from_segment_start; + + $cached_array_keys_for_current_segment = array(); + + while ( $from_base_fragment_index < $from_segment_end ) { + $from_base_fragment = $from_fragments[$from_base_fragment_index]; + $from_base_fragment_length = strlen($from_base_fragment); + // performance boost: cache array keys + if ( !isset($cached_array_keys_for_current_segment[$from_base_fragment]) ) { + if ( !isset($cached_array_keys[$from_base_fragment]) ) { + $to_all_fragment_indices = $cached_array_keys[$from_base_fragment] = array_keys($to_fragments, $from_base_fragment, true); + } + else { + $to_all_fragment_indices = $cached_array_keys[$from_base_fragment]; + } + // get only indices which falls within current segment + if ( $to_segment_start > 0 || $to_segment_end < $to_text_len ) { + $to_fragment_indices = array(); + foreach ( $to_all_fragment_indices as $to_fragment_index ) { + if ( $to_fragment_index < $to_segment_start ) { continue; } + if ( $to_fragment_index >= $to_segment_end ) { break; } + $to_fragment_indices[] = $to_fragment_index; + } + $cached_array_keys_for_current_segment[$from_base_fragment] = $to_fragment_indices; + } + else { + $to_fragment_indices = $to_all_fragment_indices; + } + } + else { + $to_fragment_indices = $cached_array_keys_for_current_segment[$from_base_fragment]; + } + // iterate through collected indices + foreach ( $to_fragment_indices as $to_base_fragment_index ) { + $fragment_index_offset = $from_base_fragment_length; + // iterate until no more match + for (;;) { + $fragment_from_index = $from_base_fragment_index + $fragment_index_offset; + if ( $fragment_from_index >= $from_segment_end ) { + break; + } + $fragment_to_index = $to_base_fragment_index + $fragment_index_offset; + if ( $fragment_to_index >= $to_segment_end ) { + break; + } + if ( $from_fragments[$fragment_from_index] !== $to_fragments[$fragment_to_index] ) { + break; + } + $fragment_length = strlen($from_fragments[$fragment_from_index]); + $fragment_index_offset += $fragment_length; + } + if ( $fragment_index_offset > $best_copy_length ) { + $best_copy_length = $fragment_index_offset; + $best_from_start = $from_base_fragment_index; + $best_to_start = $to_base_fragment_index; + } + } + $from_base_fragment_index += strlen($from_base_fragment); + // If match is larger than half segment size, no point trying to find better + // TODO: Really? + if ( $best_copy_length >= $from_segment_length / 2) { + break; + } + // no point to keep looking if what is left is less than + // current best match + if ( $from_base_fragment_index + $best_copy_length >= $from_segment_end ) { + break; + } + } + + if ( $best_copy_length ) { + $jobs[] = array($from_segment_start, $best_from_start, $to_segment_start, $best_to_start); + $result[$best_from_start * 4 + 2] = new FineDiffCopyOp($best_copy_length); + $jobs[] = array($best_from_start + $best_copy_length, $from_segment_end, $best_to_start + $best_copy_length, $to_segment_end); + } + else { + $result[$from_segment_start * 4 ] = new FineDiffReplaceOp($from_segment_length, substr($to_text, $to_segment_start, $to_segment_length)); + } + } + + ksort($result, SORT_NUMERIC); + return array_values($result); + } + + /** + * Perform a character-level diff. + * + * The algorithm is quite similar to doFragmentDiff(), except that + * the code path is optimized for character-level diff -- strpos() is + * used to find out the longest common subequence of characters. + * + * We try to find a match using the longest possible subsequence, which + * is at most the length of the shortest of the two strings, then incrementally + * reduce the size until a match is found. + * + * I still need to study more the performance of this function. It + * appears that for long strings, the generic doFragmentDiff() is more + * performant. For word-sized strings, doCharDiff() is somewhat more + * performant. + */ + private static function doCharDiff($from_text, $to_text) { + $result = array(); + $jobs = array(array(0, strlen($from_text), 0, strlen($to_text))); + while ( $job = array_pop($jobs) ) { + // get the segments which must be diff'ed + list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job; + $from_segment_len = $from_segment_end - $from_segment_start; + $to_segment_len = $to_segment_end - $to_segment_start; + + // catch easy cases first + if ( !$from_segment_len || !$to_segment_len ) { + if ( $from_segment_len ) { + $result[$from_segment_start * 4 + 0] = new FineDiffDeleteOp($from_segment_len); + } + else if ( $to_segment_len ) { + $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_len)); + } + continue; + } + if ( $from_segment_len >= $to_segment_len ) { + $copy_len = $to_segment_len; + while ( $copy_len ) { + $to_copy_start = $to_segment_start; + $to_copy_start_max = $to_segment_end - $copy_len; + while ( $to_copy_start <= $to_copy_start_max ) { + $from_copy_start = strpos(substr($from_text, $from_segment_start, $from_segment_len), substr($to_text, $to_copy_start, $copy_len)); + if ( $from_copy_start !== false ) { + $from_copy_start += $from_segment_start; + break 2; + } + $to_copy_start++; + } + $copy_len--; + } + } + else { + $copy_len = $from_segment_len; + while ( $copy_len ) { + $from_copy_start = $from_segment_start; + $from_copy_start_max = $from_segment_end - $copy_len; + while ( $from_copy_start <= $from_copy_start_max ) { + $to_copy_start = strpos(substr($to_text, $to_segment_start, $to_segment_len), substr($from_text, $from_copy_start, $copy_len)); + if ( $to_copy_start !== false ) { + $to_copy_start += $to_segment_start; + break 2; + } + $from_copy_start++; + } + $copy_len--; + } + } + // match found + if ( $copy_len ) { + $jobs[] = array($from_segment_start, $from_copy_start, $to_segment_start, $to_copy_start); + $result[$from_copy_start * 4 + 2] = new FineDiffCopyOp($copy_len); + $jobs[] = array($from_copy_start + $copy_len, $from_segment_end, $to_copy_start + $copy_len, $to_segment_end); + } + // no match, so delete all, insert all + else { + $result[$from_segment_start * 4] = new FineDiffReplaceOp($from_segment_len, substr($to_text, $to_segment_start, $to_segment_len)); + } + } + ksort($result, SORT_NUMERIC); + return array_values($result); + } + + /** + * Efficiently fragment the text into an array according to + * specified delimiters. + * No delimiters means fragment into single character. + * The array indices are the offset of the fragments into + * the input string. + * A sentinel empty fragment is always added at the end. + * Careful: No check is performed as to the validity of the + * delimiters. + */ + private static function extractFragments($text, $delimiters) { + // special case: split into characters + if ( empty($delimiters) ) { + $chars = str_split($text, 1); + $chars[strlen($text)] = ''; + return $chars; + } + $fragments = array(); + $start = $end = 0; + for (;;) { + $end += strcspn($text, $delimiters, $end); + $end += strspn($text, $delimiters, $end); + if ( $end === $start ) { + break; + } + $fragments[$start] = substr($text, $start, $end - $start); + $start = $end; + } + $fragments[$start] = ''; + return $fragments; + } + + /** + * Stock opcode renderers + */ + private static function renderToTextFromOpcode($opcode, $from, $from_offset, $from_len) { + if ( $opcode === 'c' || $opcode === 'i' ) { + echo substr($from, $from_offset, $from_len); + } + } + + private static function renderDiffToHTMLFromOpcode($opcode, $from, $from_offset, $from_len) { + if ( $opcode === 'c' ) { + echo htmlentities(substr($from, $from_offset, $from_len)); + } + else if ( $opcode === 'd' ) { + $deletion = substr($from, $from_offset, $from_len); + if ( strcspn($deletion, " \n\r") === 0 ) { + $deletion = str_replace(array("\n","\r"), array('\n','\r'), $deletion); + } + echo '', htmlentities($deletion), ''; + } + else /* if ( $opcode === 'i' ) */ { + echo '', htmlentities(substr($from, $from_offset, $from_len)), ''; + } + } +} \ No newline at end of file diff --git a/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffCopyOp.php b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffCopyOp.php new file mode 100644 index 0000000000..82fa04fbbd --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffCopyOp.php @@ -0,0 +1,57 @@ +len = $len; + } + public function getFromLen() { + return $this->len; + } + public function getToLen() { + return $this->len; + } + public function getOpcode() { + if ( $this->len === 1 ) { + return 'c'; + } + return "c{$this->len}"; + } + public function increase($size) { + return $this->len += $size; + } +} \ No newline at end of file diff --git a/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffDeleteOp.php b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffDeleteOp.php new file mode 100644 index 0000000000..8a182134da --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffDeleteOp.php @@ -0,0 +1,54 @@ +fromLen = $len; + } + public function getFromLen() { + return $this->fromLen; + } + public function getToLen() { + return 0; + } + public function getOpcode() { + if ( $this->fromLen === 1 ) { + return 'd'; + } + return "d{$this->fromLen}"; + } +} \ No newline at end of file diff --git a/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffInsertOp.php b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffInsertOp.php new file mode 100644 index 0000000000..fdb4b5c7ce --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffInsertOp.php @@ -0,0 +1,58 @@ +text = $text; + } + public function getFromLen() { + return 0; + } + public function getToLen() { + return strlen($this->text); + } + public function getText() { + return $this->text; + } + public function getOpcode() { + $to_len = strlen($this->text); + if ( $to_len === 1 ) { + return "i:{$this->text}"; + } + return "i{$to_len}:{$this->text}"; + } +} \ No newline at end of file diff --git a/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffOp.php b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffOp.php new file mode 100644 index 0000000000..dcfcaa8a68 --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/GorHill/FineDiff/FineDiffOp.php @@ -0,0 +1,42 @@ +fromLen = $fromLen; + $this->text = $text; + } + public function getFromLen() { + return $this->fromLen; + } + public function getToLen() { + return strlen($this->text); + } + public function getText() { + return $this->text; + } + public function getOpcode() { + if ( $this->fromLen === 1 ) { + $del_opcode = 'd'; + } + else { + $del_opcode = "d{$this->fromLen}"; + } + $to_len = strlen($this->text); + if ( $to_len === 1 ) { + return "{$del_opcode}i:{$this->text}"; + } + return "{$del_opcode}i{$to_len}:{$this->text}"; + } +} \ No newline at end of file diff --git a/lib/vendor/gorhill/php-fine-diff/README b/lib/vendor/gorhill/php-fine-diff/README new file mode 100644 index 0000000000..c0f9f4a8d9 --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/README @@ -0,0 +1,116 @@ +Files +----- + +finediff.php : where the FineDiff class is defined, standalone, no dependencies + +viewdiff-ex.php : demo page, render diff in HTML, show opcodes and other stats +sample_from.txt : sample text file for demo +sample_to.txt : sample text file for demo +[Text_Diff] : required for viewdiff-ex.php demo page, + available at http://download.pear.php.net/package/Text_Diff-1.1.1.tgz + +viewdiff.php : demo page, plainly render diff in HTML + +Demo can be seen online at: +http://www.raymondhill.net/finediff/ + + +Main Class: FineDiff +-------------------- + +A class which implements a high-granularity (though selectable) diff engine. +Up to character-level diffs can be computed. + +A diff is described by a string of opcodes, which can be stored +and combined later with the left hand string to re-create the +right-hand string. + +The code was started from scratch, with particular attention to +performance. The key to the performance of the FineDiff engine is +to incrementally increase the granularity. + + +Usage +----- + +The simplest way to create a diff of two strings is as follow: + + include 'finediff.php'; + $opcodes = FineDiff::getDiffOpcodes($from_text, $to_text /, default granularity is set to character */); + // store opcodes for later use... + +Later, $to_text can be re-created from $from_text using $opcodes as follow: + + include 'finediff.php'; + $to_text = FineDiff::renderToTextFromOpcodes($from_text, $opcodes); + +If you wish a different granularity from the default one, you can use +one of the provided stock granularity stacks: + + FineDiff::$paragraphGranularity + FineDiff::$sentenceGranularity + FineDiff::$wordGranularity + FineDiff::$characterGranularity (default) + +A basic HTML renderer is provided: + + echo FineDiff::renderDiffToHTMLFromOpcodes($from_text, $opcodes); + + +Customize +--------- + +It is possible to customize the engine by providing a custom "granularity stack" +at your own risk. + +It is also possible to provide a custom renderer through a user supplied callback +function/method: + + FineDiff::renderFromOpcodes($from, $opcodes, $callback); + + +FAQ +--- + +* Does it work with UTF-8? + As of now, the code assume single-byte characters. To use UTF-8 text, you can + always convert the encoding using mb_convert_encoding(): + ... + $from_text = mb_convert_encoding($from_text_utf8, 'HTML-ENTITIES', 'UTF-8'); + $to_text = mb_convert_encoding($to_text_utf8, 'HTML-ENTITIES', 'UTF-8'); + $diff_opcodes = FineDiff::getDiffOpcodes($from_text, $to_text); + ... + + If ever you want to re-generate the $to_text_utf8 from the $from_text_utf8: + ... + $from_text = mb_convert_encoding($from_text_utf8, 'HTML-ENTITIES', 'UTF-8'); + $to_text = FineDiff::renderToTextFromOpcodes($from_text, $diff_opcodes); + $to_text_utf8 = mb_convert_encoding($to_text, 'UTF-8', 'HTML-ENTITIES'); + .... + + +License +------- + +Copyright (c) 2011 Raymond Hill (http://raymondhill.net/blog/?p=441) + +Licensed under The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/lib/vendor/gorhill/php-fine-diff/composer.json b/lib/vendor/gorhill/php-fine-diff/composer.json new file mode 100644 index 0000000000..54e914e2fa --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/composer.json @@ -0,0 +1,32 @@ +{ + "name": "gorhill/PHP-FineDiff", + "type": "library", + "description": "", + "homepage": "http://www.raymondhill.net/finediff/", + "license": [ + "MIT" + ], + "keywords": [ + "FineDiff" + ], + "version": "0.1.0", + "authors": [ + { + "name": "Raymond Hill", + "email": "r.michael@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "Developer" + }, + { + "name": "Falk Gräser", + "email": "f.graeser@queo-group.com", + "homepage": "http://www.queoflow.com/", + "role": "The-Clean-Up-Guy" + } + ], + "autoload": { + "psr-4": { + "GorHill\\FineDiff\\": "GorHill/FineDiff" + } + } +} diff --git a/lib/vendor/gorhill/php-fine-diff/sample_from.txt b/lib/vendor/gorhill/php-fine-diff/sample_from.txt new file mode 100644 index 0000000000..87c3b3a86e --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/sample_from.txt @@ -0,0 +1,27 @@ +[Excerpt from Wikipedia, the free encyclopedia: Revision as of 15:00, 12 August 2010] + +Universe + +The Universe is commonly defined as the totality of everything that exists,[1] including all physical matter and energy, the planets, stars, galaxies, and the contents of intergalactic space[2][3], although this usage may differ with the context (see definitions, below). The term Universe may be used in slightly different contextual senses, denoting such concepts as the cosmos, the world, or nature. + +Observations of earlier stages in the development of the universe, which can be seen at great distances, suggest that the Universe has been governed by the same physical laws and constants throughout most of its extent and history. + +History + +Throughout recorded history, several cosmologies and cosmogonies have been proposed to account for observations of the Universe. The earliest quantitative geocentric models were developed by the ancient Greeks, who proposed that the Universe possesses infinite space and has existed eternally, but contains a single set of concentric spheres of finite size - corresponding to the fixed stars, the Sun and various planets - rotating about a spherical but unmoving Earth. Over the centuries, more precise observations and improved theories of gravity led to Copernicus's heliocentric model and the Newtonian model of the Solar System, respectively. Further improvements in astronomy led to the realization that the Solar System is embedded in a galaxy composed of millions of stars, the Milky Way, and that other galaxies exist outside it, as far as astronomical instruments can reach. Careful studies of the distribution of these galaxies and their spectral lines have led to much of modern cosmology. Discovery of the red shift and cosmic microwave background radiation revealed that the Universe is expanding and apparently had a beginning. + +According to the prevailing scientific model of the Universe, known as the Big Bang, the Universe expanded from an extremely hot, dense phase called the Planck epoch, in which all the matter and energy of the observable universe was concentrated. Since the Planck epoch, the Universe has been expanding to its present form, possibly with a brief period (less than 10-32 seconds) of cosmic inflation. Several independent experimental measurements support this theoretical expansion and, more generally, the Big Bang theory. Recent observations indicate that this expansion is accelerating because of dark energy, and that most of the matter in the Universe may be in a form which cannot be detected by present instruments, and so is not accounted for in the present models of the universe; this has been named dark matter. The imprecision of current observations has hindered predictions of the ultimate fate of the Universe. + +Current interpretations of astronomical observations indicate that the age of the Universe is 13.75 ±0.17 billion years,[4] and that the diameter of the observable universe is at least 93 billion light years, or 8.80 ×1026 metres.[5] According to general relativity, space can expand faster than the speed of light, although we can view only a small portion of the universe due to the limitation imposed by light speed. Since we cannot observe space beyond the limitations of light (or any electromagnetic radiation), it is uncertain whether the size of the Universe is finite or infinite. + +Size, age, contents, structure, and laws + +The Universe is very large and possibly infinite in volume; the observable matter is spread over a space at least 92 billion light years across.[16] For comparison, the diameter of a typical galaxy is only 30,000 light-years, and the typical distance between two neighboring galaxies is only 3 million light-years.[17] As an example, our Milky Way Galaxy is roughly 100,000 light years in diameter,[18] and our nearest sister galaxy, the Andromeda Galaxy, is located roughly 2.5 million light years away.[19] There are probably more than 100 billion (1011) galaxies in the observable universe.[20] Typical galaxies range from dwarfs with as few as ten million[21] (107) stars up to giants with one trillion[22] (1012) stars, all orbiting the galaxy's center of mass. Thus, a very rough estimate from these numbers would suggest there are around one sextillion (1021) stars in the observable universe; though a 2003 study by Australian National University astronomers resulted in a figure of 70 sextillion (7 x 1022)[23]. + +The observable matter is spread uniformly (homogeneously) throughout the universe, when averaged over distances longer than 300 million light-years.[24] However, on smaller length-scales, matter is observed to form "clumps", i.e., to cluster hierarchically; many atoms are condensed into stars, most stars into galaxies, most galaxies into clusters, superclusters and, finally, the largest-scale structures such as the Great Wall of galaxies. The observable matter of the Universe is also spread isotropically, meaning that no direction of observation seems different from any other; each region of the sky has roughly the same content.[25] The Universe is also bathed in a highly isotropic microwave radiation that corresponds to a thermal equilibrium blackbody spectrum of roughly 2.725 kelvin.[26] The hypothesis that the large-scale Universe is homogeneous and isotropic is known as the cosmological principle,[27] which is supported by astronomical observations. + +The present overall density of the Universe is very low, roughly 9.9 × 10-30 grams per cubic centimetre. This mass-energy appears to consist of 73% dark energy, 23% cold dark matter and 4% ordinary matter. Thus the density of atoms is on the order of a single hydrogen atom for every four cubic meters of volume.[28] The properties of dark energy and dark matter are largely unknown. Dark matter gravitates as ordinary matter, and thus works to slow the expansion of the Universe; by contrast, dark energy accelerates its expansion. + +The Universe is old and evolving. The most precise estimate of the Universe's age is 13.73±0.12 billion years old, based on observations of the cosmic microwave background radiation.[29] Independent estimates (based on measurements such as radioactive dating) agree, although they are less precise, ranging from 11-20 billion years[30] to 13-15 billion years.[31] The universe has not been the same at all times in its history; for example, the relative populations of quasars and galaxies have changed and space itself appears to have expanded. This expansion accounts for how Earth-bound scientists can observe the light from a galaxy 30 billion light years away, even if that light has traveled for only 13 billion years; the very space between them has expanded. This expansion is consistent with the observation that the light from distant galaxies has been redshifted; the photons emitted have been stretched to longer wavelengths and lower frequency during their journey. The rate of this spatial expansion is accelerating, based on studies of Type Ia supernovae and corroborated by other data. + +... diff --git a/lib/vendor/gorhill/php-fine-diff/sample_to.txt b/lib/vendor/gorhill/php-fine-diff/sample_to.txt new file mode 100644 index 0000000000..26551b10fd --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/sample_to.txt @@ -0,0 +1,26 @@ +[Excerpt from Wikipedia, the free encyclopedia: Revision as of 19:58, 19 February 2011] + +Universe + +The universe is commonly defined as the totality of everything that exists,[1] including all physical matter and energy, the planets, stars, galaxies, and the contents of intergalactic space,[2][3] although this usage may differ with the context (see definitions, below). The term universe may be used in slightly different contextual senses, denoting such concepts as the cosmos, the world, or nature. Observations of earlier stages in the development of the universe, which can be seen at great distances, suggest that the universe has been governed by the same physical laws and constants throughout most of its extent and history. + +History + +Throughout recorded history, several cosmologies and cosmogonies have been proposed to account for observations of the universe. The earliest quantitative geocentric models were developed by the ancient Greeks, who proposed that the universe possesses infinite space and has existed eternally, but contains a single set of concentric spheres of finite size - corresponding to the fixed stars, the Sun and various planets - rotating about a spherical but unmoving Earth. Over the centuries, more precise observations and improved theories of gravity led to Copernicus's heliocentric model and the Newtonian model of the Solar System, respectively. Further improvements in astronomy led to the realization that the Solar System is embedded in a galaxy composed of billions of stars, the Milky Way, and that other galaxies exist outside it, as far as astronomical instruments can reach. Careful studies of the distribution of these galaxies and their spectral lines have led to much of modern cosmology. Discovery of the red shift and cosmic microwave background radiation revealed that the universe is expanding and apparently had a beginning. + +According to the prevailing scientific model of the universe, known as the Big Bang, the universe expanded from an extremely hot, dense phase called the Planck epoch, in which all the matter and energy of the observable universe was concentrated. Since the Planck epoch, the universe has been expanding to its present form, possibly with a brief period (less than 10-32 seconds) of cosmic inflation. Several independent experimental measurements support this theoretical expansion and, more generally, the Big Bang theory. Recent observations indicate that this expansion is accelerating because of dark energy, and that most of the matter in the universe may be in a form which cannot be detected by present instruments, and so is not accounted for in the present models of the universe; this has been named dark matter. The imprecision of current observations has hindered predictions of the ultimate fate of the universe. + +Current interpretations of astronomical observations indicate that the age of the universe is 13.75 ±0.17 billion years,[4] and that the diameter of the observable universe is at least 93 billion light years or 8.80×1026 +metres.[5] According to general relativity, space can expand faster than the speed of light, although we can view only a small portion of the universe due to the limitation imposed by light speed. Since we cannot observe space beyond the limitations of light (or any electromagnetic radiation), it is uncertain whether the size of the universe is finite or infinite. + +Size, age, contents, structure, and laws + +The universe is immensely large and possibly infinite in volume. The region visible from Earth (the observable universe) is a sphere with a radius of about 46 billion light years,[16] based on where the expansion of space has taken the most distant objects observed. For comparison, the diameter of a typical galaxy is only 30,000 light-years, and the typical distance between two neighboring galaxies is only 3 million light-years.[17] As an example, our Milky Way Galaxy is roughly 100,000 light years in diameter,[18] and our nearest sister galaxy, the Andromeda Galaxy, is located roughly 2.5 million light years away.[19] There are probably more than 100 billion (1011) galaxies in the observable universe.[20] Typical galaxies range from dwarfs with as few as ten million[21] (107) stars up to giants with one trillion[22] (1012) stars, all orbiting the galaxy's center of mass. Thus, a very rough estimate from these numbers would suggest there are around one sextillion (1021) stars in the observable universe; though a 2010 study by astronomers resulted in a figure of 300 sextillion (3×1023).[23] + +The observable matter is spread uniformly (homogeneously) throughout the universe, when averaged over distances longer than 300 million light-years.[24] However, on smaller length-scales, matter is observed to form "clumps", i.e., to cluster hierarchically; many atoms are condensed into stars, most stars into galaxies, most galaxies into clusters, superclusters and, finally, the largest-scale structures such as the Great Wall of galaxies. The observable matter of the universe is also spread isotropically, meaning that no direction of observation seems different from any other; each region of the sky has roughly the same content.[25] The universe is also bathed in a highly isotropic microwave radiation that corresponds to a thermal equilibrium blackbody spectrum of roughly 2.725 kelvin.[26] The hypothesis that the large-scale universe is homogeneous and isotropic is known as the cosmological principle,[27] which is supported by astronomical observations. + +The present overall density of the universe is very low, roughly 9.9 × 10-30 grams per cubic centimetre. This mass-energy appears to consist of 73% dark energy, 23% cold dark matter and 4% ordinary matter. Thus the density of atoms is on the order of a single hydrogen atom for every four cubic meters of volume.[28] The properties of dark energy and dark matter are largely unknown. Dark matter gravitates as ordinary matter, and thus works to slow the expansion of the universe; by contrast, dark energy accelerates its expansion. + +The most precise estimate of the universe's age is 13.73±0.12 billion years old, based on observations of the cosmic microwave background radiation.[29] Independent estimates (based on measurements such as radioactive dating) agree, although they are less precise, ranging from 11-20 billion years[30] to 13-15 billion years.[31] The universe has not been the same at all times in its history; for example, the relative populations of quasars and galaxies have changed and space itself appears to have expanded. This expansion accounts for how Earth-bound scientists can observe the light from a galaxy 30 billion light years away, even if that light has traveled for only 13 billion years; the very space between them has expanded. This expansion is consistent with the observation that the light from distant galaxies has been redshifted; the photons emitted have been stretched to longer wavelengths and lower frequency during their journey. The rate of this spatial expansion is accelerating, based on studies of Type Ia supernovae and corroborated by other data. + +... diff --git a/lib/vendor/gorhill/php-fine-diff/viewdiff-ex.php b/lib/vendor/gorhill/php-fine-diff/viewdiff-ex.php new file mode 100644 index 0000000000..5a56d1f22a --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/viewdiff-ex.php @@ -0,0 +1,301 @@ + + + + +PHP Fine Diff + + +
      Fork me on GitHub +

      PHP Fine Diff

      +
      +

      This page demonstrate the FineDiff class (as in “fine granularity diff”) I wrote – starting from scratch – to generate a lossless (won't eat your line breaks), compact opcodes string listing the sequence of atomic actions (copy/delete/insert) necessary to transform one string into another (thereafter referred as the “From” and “To” string). The “To” string can be rebuilt by running the opcodes string on the “From” string. The FineDiff class allows to specify the granularity, and up to character-level granularity is possible, in order to generate the smallest diff possible (at the potential cost of increased CPU cycles.)

      +

      Typical usage:

      +

      +include 'finediff.php';
      +$opcodes = FineDiff::getDiffOpcodes($from_text, $to_text /* , default granularity is set to character */);
      +// store opcodes for later use...

      +

      Later, $to_text can be re-created from $from_text using $opcodes as follow:

      +

      +include 'finediff.php';
      +$to_text = FineDiff::renderToTextFromOpcodes($from_text, $opcodes); +

      +

      Try it by inserting your own text, or Use sample text, or Start from scratch, or just use the plain Online diff viewer:

      +getDiff() as $edit ) { + if ( $edit instanceof Text_Diff_Op_copy ) { + $orig = str_replace(array("\1","\2"), array("\n","\r"), implode('', $edit->orig)); + $edits[] = new fineDiffCopyOp(strlen($orig)); + echo htmlentities($orig); + } + else if ( $edit instanceof Text_Diff_Op_delete ) { + $orig = str_replace(array("\1","\2"), array("\n","\r"), implode('', $edit->orig)); + $edits[] = new fineDiffDeleteOp(strlen($orig)); + echo '', htmlentities($orig), ''; + } + else if ( $edit instanceof Text_Diff_Op_add ) { + $final = str_replace(array("\1","\2"), array("\n","\r"), implode('', $edit->final)); + $edits[] = new fineDiffInsertOp($final); + echo '', htmlentities($final), ''; + } + else if ( $edit instanceof Text_Diff_Op_change ) { + $orig = str_replace(array("\1","\2"), array("\n","\r"), implode('', $edit->orig)); + $final = str_replace(array("\1","\2"), array("\n","\r"), implode('', $edit->final)); + $edits[] = new fineDiffReplaceOp(strlen($orig), $final); + echo '', htmlentities($orig), ''; + echo '', htmlentities($final), ''; + } + } + $rendered_diff = ob_get_clean(); + $rendering_time = sprintf('%.3f sec', gettimeofday(true) - $start_time); + } + // character-level granularity not allowed + else { + $edits = false; + $exec_time = '?'; + $rendering_time = '?'; + $rendered_diff = 'Character-level granularity not allowed when using Text_Diff, due to performance issues.'; + } + } +else { + $granularityStacks = array( + FineDiff::$paragraphGranularity, + FineDiff::$sentenceGranularity, + FineDiff::$wordGranularity, + FineDiff::$characterGranularity + ); + + $diff = new FineDiff($from, $to, $granularityStacks[$granularity]); + $edits = $diff->getOps(); + $exec_time = sprintf('%.3f sec', gettimeofday(true) - $start_time); + $rendered_diff = $diff->renderDiffToHTML(); + $rendering_time = sprintf('%.3f sec', gettimeofday(true) - $start_time); + } + +if ( $edits !== false ) { + $opcodes = array(); + $opcodes_len = 0; + foreach ( $edits as $edit ) { + $opcode = $edit->getOpcode(); + $opcodes_len += strlen($opcode); + $opcode = htmlentities($opcode); + if ( $edit instanceof FineDiffCopyOp ) { + $opcodes[] = "{$opcode}"; + } + else if ( $edit instanceof FineDiffDeleteOp ) { + $opcodes[] = "{$opcode}"; + } + else if ( $edit instanceof FineDiffInsertOp ) { + $opcodes[] = "{$opcode}"; + } + else /* if ( $edit instanceof FineDiffReplaceOp ) */ { + $opcodes[] = "{$opcode}"; + } + } + $opcodes = implode("", $opcodes); + $opcodes_len = sprintf('%d bytes (%.1f %% of "To")', $opcodes_len, $to_len ? $opcodes_len * 100 / $to_len : 0); + } +else { + $opcodes = '?'; + $opcodes_len = '?'; + } +?> +
      +

      From:

      +

      To:

      +

      Granularity:> Paragraph/lines > Sentence > Word > Character  >Text_Diff lib (for comparison purpose) see notes

      +
      +

      Diff stats:

      +Diff execution time:
      +Diff execution + rendering time:
      +"From" size: bytes
      +"To" size: bytes
      +Diff opcodes size:
      +Diff opcodes ( =copy,  =delete,  =insert,  =replace): +
      +
      +

      Rendered Diff: Show Deletions only All Insertions only

      +
      +
      +
      +
      + +
      +
      +

      Notes

      +

      The PHP-based engine of Text_Diff is forced, in order to meaningfully compare results with PHP-based FineDiff. Text_Diff is naturally geared toward line-level granularity, and to compute diff for a higher granularity (sequences, words, characters), line break characters (\n, \r) are replaced in order to avoid having Text_Diff from eating our line breaks — so extra steps are required.

      +

      FineDiff is natively better equipped to generate diff at granularity higher than line levels. An example of this is that using the above built-in sample text, for word and character-level granularity, FineDiff roughly executes in 25 ms and 30 ms, respectively, while Text_Diff roughly executes in 75 ms and 6.5 seconds, respectively (on my development computer, a run of the mill Intel i5 core desktop computer).

      +

      If you wish to comment on this page, head to the associated blog entry: FineDiff, a character-level diff algorithm in PHP

      +
      + + diff --git a/lib/vendor/gorhill/php-fine-diff/viewdiff.php b/lib/vendor/gorhill/php-fine-diff/viewdiff.php new file mode 100644 index 0000000000..64c390ca5f --- /dev/null +++ b/lib/vendor/gorhill/php-fine-diff/viewdiff.php @@ -0,0 +1,177 @@ + + + + +PHP Fine Diff: Online Diff Viewer + + + +Fork me on GitHub +

      PHP Fine Diff: Online Diff Viewer

      +
      +The page you are looking for has expired.

      ', "\n"; + } + } + $exec_time = gettimeofday(true) - $start_time; + } +// new diff +else { + if ( isset($_POST['granularity']) && ctype_digit($_POST['granularity']) ) { + $granularity = max(min(intval($_POST['granularity']),3),0); + } + if ( !empty($_POST['from']) || !empty($_POST['to'])) { + if ( !empty($_POST['from']) ) { + $from_text = $_POST['from']; + } + if ( !empty($_POST['to']) ) { + $to_text = $_POST['to']; + } + } + // limit input + $from_text = substr($from_text, 0, 1024*100); + $to_text = substr($to_text, 0, 1024*100); + + // ensure input is suitable for diff + $from_text = mb_convert_encoding($from_text, 'HTML-ENTITIES', 'UTF-8'); + $to_text = mb_convert_encoding($to_text, 'HTML-ENTITIES', 'UTF-8'); + + $granularityStacks = array( + FineDiff::$paragraphGranularity, + FineDiff::$sentenceGranularity, + FineDiff::$wordGranularity, + FineDiff::$characterGranularity + ); + $diff_opcodes = FineDiff::getDiffOpcodes($from_text, $to_text, $granularityStacks[$granularity]); + $diff_opcodes_len = strlen($diff_opcodes); + $exec_time = gettimeofday(true) - $start_time; + if ( $diff_opcodes_len ) { + $data_key = sha1(serialize(array('granularity' => $granularity, 'from_text' => $from_text, 'diff_opcodes' => $diff_opcodes))); + $filename = "{$data_key}{$compressed_serialized_filename_extension}"; + if ( !file_exists("./cache/{$filename}") ) { + // purge cache if too many files + if ( !(time() % 100) ) { + $files = glob("./cache/*{$compressed_serialized_filename_extension}"); + $num_files = $files ? count($files) : 0; + if ( $num_files > $cache_hi_water_mark ) { + $sorted_files = array(); + foreach ( $files as $file ) { + $sorted_files[strval(@filemtime("./cache/{$file}")).$file] = $file; + } + ksort($sorted_files); + foreach ( $sorted_files as $file ) { + @unlink("./cache/{$file}"); + $num_files -= 1; + if ( $num_files < $cache_lo_water_mark ) { + break; + } + } + } + } + // save diff in cache + $data_to_serialize = array( + 'granularity' => $granularity, + 'from_text' => $from_text, + 'diff_opcodes' => $diff_opcodes, + 'data_key' => $data_key, + ); + $serialized_data = serialize($data_to_serialize); + @file_put_contents("./cache/{$filename}", gzcompress($serialized_data)); + @chmod("./cache/{$filename}", 0666); + } + } + } + +$rendered_diff = FineDiff::renderDiffToHTMLFromOpcodes($from_text, $diff_opcodes); +$from_len = strlen($from_text); +$to_len = strlen($to_text); + +if ( !empty($data_key) ) { + echo '

      Tempolink: http://', $_SERVER['HTTP_HOST'], '/viewdiff.php?data=', $data_key, ' (This link is not viewable by others, unless it has been explicitly shared by the creator. This link will exist for a limited period of time, which depends on how often it is visited.)

      ', "\n"; + } +?> +

      Diff (diff: seconds, diff len: chars) / Show Deletions only All Insertions only

      +
      +
      +

      Enter text to diff below:

      +

      From

      +

      To

      +

      Granularity:> Paragraph/lines > Sentence > Word > Character  

      +
      +

      Go to main page

      + + + diff --git a/lib/vendor/gregwar/captcha/LICENSE b/lib/vendor/gregwar/captcha/LICENSE new file mode 100644 index 0000000000..62f991a6ab --- /dev/null +++ b/lib/vendor/gregwar/captcha/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) <2012-2017> Grégoire Passault + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lib/vendor/gregwar/captcha/README.md b/lib/vendor/gregwar/captcha/README.md new file mode 100644 index 0000000000..baef46e632 --- /dev/null +++ b/lib/vendor/gregwar/captcha/README.md @@ -0,0 +1,150 @@ +Captcha +======= + +![Captchas examples](http://gregwar.com/captchas.png) +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YUXRLWHQSWS6L) + +Installation +============ + +With composer : + +``` json +{ + ... + "require": { + "gregwar/captcha": "1.*" + } +} +``` + +Usage +===== + +You can create a captcha with the `CaptchaBuilder` : + +```php +build(); +``` + +You can then save it to a file : + +```php +save('out.jpg'); +``` + +Or output it directly : + +```php +output(); +``` + +Or inline it directly in the HTML page: + +```php + +``` + +You'll be able to get the code and compare it with a user input : + +```php +getPhrase(); +``` + +You can compare the phrase with user input: +```php +if($builder->testPhrase($userInput)) { + // instructions if user phrase is good +} +else { + // user phrase is wrong +} +``` + +API +=== + +You can use these functions : + +* **__construct($phrase = null)**, constructs the builder with the given phrase, if the phrase is null, a random one will be generated +* **getPhrase()**, allow you to get the phrase contents +* **setDistortion($distortion)**, enable or disable the distortion, call it before `build()` +* **isOCRReadable()**, returns `true` if the OCR can be read using the `ocrad` software, you'll need to have shell_exec enabled, imagemagick and ocrad installed +* **buildAgainstOCR($width = 150, $height = 40, $font = null)**, builds a code until it is not readable by `ocrad` +* **build($width = 150, $height = 40, $font = null)**, builds a code with the given $width, $height and $font. By default, a random font will be used from the library +* **save($filename, $quality = 80)**, saves the captcha in the $filename, with the given quality +* **get($quality = 80)**, returns the image data +* **output($quality = 80)**, directly outputs the image +* **inline($quality = 80)**, returns the jpeg code directly in the HTML page +* **setBackgroundColor($r, $g, $b)**, sets the background color to force it (this will disable many effects and is not recommended) +* **setBackgroundAlpha($alpha)**, sets the background transparency 0 is fully opaque, 127 is fully transparent +* **setBackgroundImages(array($imagepath1, $imagePath2))**, Sets custom background images to be used as captcha background. It is recommended to disable image effects when passing custom images for background (ignore_all_effects). A random image is selected from the list passed, the full paths to the image files must be passed. +* **setInterpolation($interpolate)**, enable or disable the interpolation (enabled by default), disabling it will be quicker but the images will look uglier +* **setIgnoreAllEffects($ignoreAllEffects)**, disable all effects on the captcha image. Recommended to use when passing custom background images for the captcha. +* **testPhrase($phrase)**, returns true if the given phrase is good +* **setMaxBehindLines($lines)**, sets the maximum number of lines behind the code +* **setMaxFrontLines($lines)**, sets the maximum number of lines on the front of the code +* **setImageType($type)**, sets the image output type to "jpeg", "png" or "gif" +* **setScatterEffect($bool)**, enable or disable scatter effect (fuzzyness) + +If you want to change the number of character, you can call the phrase builder directly using +extra parameters: + +```php +use Gregwar\Captcha\CaptchaBuilder; +use Gregwar\Captcha\PhraseBuilder; + +// Will build phrases of 3 characters +$phraseBuilder = new PhraseBuilder(4); + +// Will build phrases of 5 characters, only digits +$phraseBuilder = new PhraseBuilder(5, '0123456789'); + +// Pass it as first argument of CaptchaBuilder, passing it the phrase +// builder +$captcha = new CaptchaBuilder(null, $phraseBuilder); +``` + +You can also pass directly the wanted phrase to the builder: + +```php +// Building a Captcha with the "hello" phrase +$captcha = new CaptchaBuilder('hello'); +``` + +Complete example +================ + +If you want to see an example you can have a look at the ``demo/form.php``, which uses ``demo/session.php`` to +render a captcha and check it after the submission + +Symfony Bundle +================ + +You can have a look at the following repository to enjoy the Symfony 2 bundle packaging this captcha generator : +https://github.com/Gregwar/CaptchaBundle + +Yii2 Extension +=============== + +You can use the following extension for integrating with Yii2 Framework : +https://github.com/juliardi/yii2-captcha + +License +======= + +This library is under MIT license, have a look to the `LICENSE` file diff --git a/lib/vendor/gregwar/captcha/composer.json b/lib/vendor/gregwar/captcha/composer.json new file mode 100644 index 0000000000..a76f5d02c5 --- /dev/null +++ b/lib/vendor/gregwar/captcha/composer.json @@ -0,0 +1,34 @@ +{ + "name": "gregwar/captcha", + "type": "library", + "description": "Captcha generator", + "keywords": ["captcha", "spam", "bot"], + "homepage": "https://github.com/Gregwar/Captcha", + "license": "MIT", + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "require": { + "php": ">=5.3.0", + "ext-gd": "*", + "ext-mbstring": "*", + "ext-fileinfo": "*", + "symfony/finder": "*" + }, + "autoload": { + "psr-4": { + "Gregwar\\": "src/Gregwar" + } + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0" + } +} diff --git a/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilder.php b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilder.php new file mode 100644 index 0000000000..0d2892ddab --- /dev/null +++ b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilder.php @@ -0,0 +1,854 @@ + + * @author Jeremy Livingston + */ +class CaptchaBuilder implements CaptchaBuilderInterface +{ + /** + * @var array + */ + protected $fingerprint = array(); + + /** + * @var bool + */ + protected $useFingerprint = false; + + /** + * @var array + */ + protected $textColor = array(); + + /** + * @var array + */ + protected $lineColor = null; + + /** + * @var array + */ + protected $backgroundColor = null; + + + /** + * @var int 0 to 127, 127 is completely transparent + */ + protected $bgAlpha = 0; + + /** + * @var array + */ + protected $backgroundImages = array(); + + /** + * @var resource|\GdImage + */ + protected $contents = null; + + /** + * @var string + */ + protected $phrase = null; + + /** + * @var PhraseBuilderInterface + */ + protected $builder; + + /** + * @var bool + */ + protected $distortion = true; + + /** + * The maximum number of lines to draw in front of + * the image. null - use default algorithm + */ + protected $maxFrontLines = null; + + /** + * The maximum number of lines to draw behind + * the image. null - use default algorithm + */ + protected $maxBehindLines = null; + + /** + * The maximum angle of char + */ + protected $maxAngle = 8; + + /** + * The maximum offset of char + */ + protected $maxOffset = 5; + + /** + * Is the interpolation enabled ? + * + * @var bool + */ + protected $interpolation = true; + + /** + * Ignore all effects + * + * @var bool + */ + protected $ignoreAllEffects = false; + + /** + * @var bool + */ + protected $scatterEffect = true; + + /** + * Allowed image types for the background images + * + * @var array + */ + protected $allowedBackgroundImageTypes = array('image/png', 'image/jpeg', 'image/gif'); + + /** + * @var string + */ + protected $imageType = "jpeg"; + + /** + * The image contents + */ + public function getContents() + { + return $this->contents; + } + + /** + * Enable/Disables the interpolation + * + * @param $interpolate bool True to enable, false to disable + * + * @return CaptchaBuilder + */ + public function setInterpolation($interpolate = true) + { + $this->interpolation = $interpolate; + + return $this; + } + + /** + * Temporary dir, for OCR check + */ + public $tempDir = 'temp/'; + + /** + * @param string|null $phrase + * @param PhraseBuilderInterface|null $builder + */ + public function __construct($phrase = null, $builder = null) + { + if ($builder !== null && !$builder instanceof PhraseBuilderInterface) { + throw new InvalidArgumentException('Builder ($builder) must implement PhraseBuilderInterface'); + } + + $this->builder = $builder ?: new PhraseBuilder(); + $this->phrase = is_string($phrase) ? $phrase : $this->builder->build($phrase); + } + + public function setImageType($imageType) + { + $imageType = is_string($imageType) ? strtolower($imageType) : ''; + if (in_array($imageType, array('png', 'jpeg', 'gif'))) { + $this->imageType = $imageType; + } + + return $this; + } + + public function getImageType() + { + return $this->imageType; + } + + /** + * Setting the phrase + */ + public function setPhrase($phrase) + { + $this->phrase = (string) $phrase; + } + + /** + * Enables/disable distortion + */ + public function setDistortion($distortion) + { + $this->distortion = (bool) $distortion; + + return $this; + } + + /** + * Enables/disable scatter effect - Only applies to PHP 7.4+ + * + * @param bool $scatterEffect + */ + public function setScatterEffect($scatterEffect) + { + if (version_compare(PHP_VERSION, '7.4.0') < 0) { + throw new LogicException('Scatter effect is only available on PHP 7.4'); + } + + $this->scatterEffect = (bool) $scatterEffect; + + return $this; + } + + public function setMaxBehindLines($maxBehindLines) + { + $this->maxBehindLines = $maxBehindLines; + + return $this; + } + + public function setMaxFrontLines($maxFrontLines) + { + $this->maxFrontLines = $maxFrontLines; + + return $this; + } + + public function setMaxAngle($maxAngle) + { + $this->maxAngle = $maxAngle; + + return $this; + } + + public function setMaxOffset($maxOffset) + { + $this->maxOffset = $maxOffset; + + return $this; + } + + /** + * Gets the captcha phrase + */ + public function getPhrase() + { + return $this->phrase; + } + + /** + * Returns true if the given phrase is good + */ + public function testPhrase($phrase) + { + return ($this->builder->niceize($phrase) == $this->builder->niceize($this->getPhrase())); + } + + /** + * Instantiation + */ + public static function create($phrase = null) + { + return new self($phrase); + } + + /** + * Sets the text color to use + */ + public function setTextColor($r, $g, $b) + { + $this->textColor = array($r, $g, $b); + + return $this; + } + + /** + * Sets the background color to use + */ + public function setBackgroundColor($r, $g, $b) + { + $this->backgroundColor = array($r, $g, $b); + + return $this; + } + + /** + * @param int $alpha 0 to 127, 127 is completely transparent + * @return $this + */ + public function setBackgroundAlpha($alpha) + { + if (! is_integer($alpha) || $alpha < 0 || $alpha > 127) { + throw new InvalidArgumentException('Argument $alpha must be an integer between 0 and 127.'); + } + + if ($this->getImageType() !== 'png') { + throw new LogicException('You can only set transparency on PNG images, call setImageType(\'png\')'); + } + + $this->bgAlpha = $alpha; + + return $this; + } + + public function getBackgroundAlpha() + { + return $this->bgAlpha; + } + + /** + * Sets the line color to use + */ + public function setLineColor($r, $g, $b) + { + $this->lineColor = array($r, $g, $b); + + return $this; + } + + /** + * Sets the ignoreAllEffects value + * + * @param bool $ignoreAllEffects + * @return CaptchaBuilder + */ + public function setIgnoreAllEffects($ignoreAllEffects) + { + $this->ignoreAllEffects = $ignoreAllEffects; + + return $this; + } + + /** + * Sets the list of background images to use (one image is randomly selected) + */ + public function setBackgroundImages(array $backgroundImages) + { + $this->backgroundImages = $backgroundImages; + + return $this; + } + + /** + * Draw lines over the image + */ + protected function drawLine($image, $width, $height, $tcol = null) + { + if ($this->lineColor === null) { + $red = $this->rand(100, 255); + $green = $this->rand(100, 255); + $blue = $this->rand(100, 255); + } else { + $red = $this->lineColor[0]; + $green = $this->lineColor[1]; + $blue = $this->lineColor[2]; + } + + if ($tcol === null) { + $tcol = imagecolorallocate($image, $red, $green, $blue); + } + + if ($this->rand(0, 1)) { // Horizontal + $Xa = $this->rand(0, $width / 2); + $Ya = $this->rand(0, $height); + $Xb = $this->rand($width / 2, $width); + $Yb = $this->rand(0, $height); + } else { // Vertical + $Xa = $this->rand(0, $width); + $Ya = $this->rand(0, $height / 2); + $Xb = $this->rand(0, $width); + $Yb = $this->rand($height / 2, $height); + } + imagesetthickness($image, $this->rand(1, 3)); + imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol); + } + + /** + * Apply some post effects + */ + protected function postEffect($image, $bg) + { + if (!function_exists('imagefilter')) { + return; + } + + if ($this->backgroundColor != null || $this->textColor != null) { + return; + } + + // Scatter/Noise - Added in PHP 7.4 + $scattered = false; + if (defined('IMG_FILTER_SCATTER')) { + if ($this->scatterEffect && $this->rand(0, 3) != 0 && $bg != null) { + $scattered = true; + imagefilter($image, IMG_FILTER_SCATTER, 0, 2, array($bg)); + } + } + + // Negate ? + if ($this->rand(0, 1) == 0) { + imagefilter($image, IMG_FILTER_NEGATE); + } + + // Edge ? + if (!$scattered && $this->rand(0, 10) == 0) { + imagefilter($image, IMG_FILTER_EDGEDETECT); + } + + // Contrast + imagefilter($image, IMG_FILTER_CONTRAST, $this->rand(-50, 10)); + + // Colorize + if (!$scattered && $this->rand(0, 5) == 0) { + imagefilter($image, IMG_FILTER_COLORIZE, $this->rand(-80, 50), $this->rand(-80, 50), $this->rand(-80, 50)); + } + } + + /** + * Writes the phrase on the image + */ + protected function writePhrase($image, $phrase, $font, $width, $height) + { + $length = mb_strlen($phrase); + if ($length === 0) { + return \imagecolorallocate($image, 0, 0, 0); + } + + // Gets the text size and start position + $size = (int) round($width / $length) - $this->rand(0, 3) - 1; + $box = \imagettfbbox($size, 0, $font, $phrase); + $textWidth = $box[2] - $box[0]; + $textHeight = $box[1] - $box[7]; + $x = (int) round(($width - $textWidth) / 2); + $y = (int) round(($height - $textHeight) / 2) + $size; + + if (!$this->textColor) { + $textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150)); + } else { + $textColor = $this->textColor; + } + $col = \imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]); + + // Write the letters one by one, with random angle + for ($i = 0; $i < $length; $i++) { + $symbol = mb_substr($phrase, $i, 1); + $box = \imagettfbbox($size, 0, $font, $symbol); + $w = $box[2] - $box[0]; + $angle = $this->rand(-$this->maxAngle, $this->maxAngle); + $offset = $this->rand(-$this->maxOffset, $this->maxOffset); + \imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $symbol); + $x += $w; + } + + return $col; + } + + /** + * Try to read the code against an OCR + */ + public function isOCRReadable() + { + if (!is_dir($this->tempDir)) { + @mkdir($this->tempDir, 0755, true); + } + + $tempj = $this->tempDir . uniqid('captcha', true) . '.jpg'; + $tempp = $this->tempDir . uniqid('captcha', true) . '.pgm'; + + $this->save($tempj); + shell_exec("convert $tempj $tempp"); + $value = trim(strtolower(shell_exec("ocrad $tempp"))); + + @unlink($tempj); + @unlink($tempp); + + return $this->testPhrase($value); + } + + /** + * Builds while the code is readable against an OCR + */ + public function buildAgainstOCR($width = 150, $height = 40, $font = null, $fingerprint = null) + { + do { + $this->build($width, $height, $font, $fingerprint); + } while ($this->isOCRReadable()); + } + + /** + * Generate the image + */ + public function build($width = 150, $height = 40, $font = null, $fingerprint = null) + { + if (null !== $fingerprint) { + $this->fingerprint = $fingerprint; + $this->useFingerprint = true; + } else { + $this->fingerprint = array(); + $this->useFingerprint = false; + } + + if ($font === null) { + $font = __DIR__ . '/Font/captcha' . $this->rand(0, 5) . '.ttf'; + } + + if (empty($this->backgroundImages)) { + // if background images list is not set, use a color fill as a background + $image = imagecreatetruecolor($width, $height); + if ($this->backgroundColor == null) { + $bg = imagecolorallocatealpha( + $image, + $this->rand(200, 255), + $this->rand(200, 255), + $this->rand(200, 255), + $this->bgAlpha + ); + } else { + $color = $this->backgroundColor; + $bg = imagecolorallocatealpha($image, $color[0], $color[1], $color[2], $this->bgAlpha); + } + imagefill($image, 0, 0, $bg); + imagesavealpha($image, true); + } else { + // use a random background image + $randomBackgroundImage = $this->backgroundImages[rand(0, count($this->backgroundImages) - 1)]; + + $imageType = $this->validateBackgroundImage($randomBackgroundImage); + + $image = $this->createBackgroundImageFromType($randomBackgroundImage, $imageType); + } + + // Apply effects + if (!$this->ignoreAllEffects) { + $square = $width * $height; + $effects = $this->rand($square / 3000, $square / 2000); + + // set the maximum number of lines to draw in front of the text + if ($this->maxBehindLines != null && $this->maxBehindLines > 0) { + $effects = min($this->maxBehindLines, $effects); + } + + if ($this->maxBehindLines !== 0) { + for ($e = 0; $e < $effects; $e++) { + $this->drawLine($image, $width, $height); + } + } + } + + // Write CAPTCHA text + $color = $this->writePhrase($image, $this->phrase, $font, $width, $height); + + // Apply effects + if (!$this->ignoreAllEffects) { + $square = $width * $height; + $effects = $this->rand($square / 3000, $square / 2000); + + // set the maximum number of lines to draw in front of the text + if ($this->maxFrontLines != null && $this->maxFrontLines > 0) { + $effects = min($this->maxFrontLines, $effects); + } + + if ($this->maxFrontLines !== 0) { + for ($e = 0; $e < $effects; $e++) { + $this->drawLine($image, $width, $height, $color); + } + } + } + + // Distort the image + if ($this->distortion && !$this->ignoreAllEffects) { + $image = $this->distort($image, $width, $height, isset($bg) ? $bg : 0); + } + + // Post effects + if (!$this->ignoreAllEffects) { + $this->postEffect($image, isset($bg) ? $bg : 0); + } + + $this->contents = $image; + + return $this; + } + + /** + * Distorts the image + */ + public function distort($image, $width, $height, $bg) + { + $contents = imagecreatetruecolor($width, $height); + imagefill($contents, 0, 0, $bg); + imagesavealpha($contents, true); + $X = $this->rand(0, $width); + $Y = $this->rand(0, $height); + $phase = $this->rand(0, 10); + $scale = 1.1 + $this->rand(0, 10000) / 30000; + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $Vx = $x - $X; + $Vy = $y - $Y; + $Vn = sqrt($Vx * $Vx + $Vy * $Vy); + + if ($Vn != 0) { + $Vn2 = $Vn + 4 * sin($Vn / 30); + $nX = $X + ($Vx * $Vn2 / $Vn); + $nY = $Y + ($Vy * $Vn2 / $Vn); + } else { + $nX = $X; + $nY = $Y; + } + $nY = $nY + $scale * sin($phase + $nX * 0.2); + + if ($this->interpolation) { + $p = $this->interpolate( + $nX - floor($nX), + $nY - floor($nY), + $this->getCol($image, floor($nX), floor($nY), $bg), + $this->getCol($image, ceil($nX), floor($nY), $bg), + $this->getCol($image, floor($nX), ceil($nY), $bg), + $this->getCol($image, ceil($nX), ceil($nY), $bg) + ); + } else { + $p = $this->getCol($image, round($nX), round($nY), $bg); + } + + if ($p == 0) { + $p = $bg; + } + + imagesetpixel($contents, $x, $y, $p); + } + } + + return $contents; + } + + /** + * Saves the Captcha to file + */ + public function save($filename, $quality = 90) + { + $imageType = $this->getImageType(); + switch ($imageType) { + case "png": + imagepng($this->contents, $filename, $quality / 10); // quality 0-9 + break; + case "gif": + imagegif($this->contents, $filename); + break; + default: + imagejpeg($this->contents, $filename, $quality); // quality 0-100 + break; + } + } + + /** + * Gets the image GD + */ + public function getGd() + { + return $this->contents; + } + + /** + * Gets the image contents + */ + public function get($quality = 90) + { + ob_start(); + $this->output($quality); + + return ob_get_clean(); + } + + /** + * Gets the HTML inline base64 + */ + public function inline($quality = 90) + { + return sprintf('data:image/%s;base64,%s', $this->getImageType(), base64_encode($this->get($quality))); + } + + /** + * Outputs the image + */ + public function output($quality = 90) + { + $this->save(null, $quality); + } + + /** + * @return array + */ + public function getFingerprint() + { + return $this->fingerprint; + } + + /** + * Returns a random number or the next number in the + * fingerprint + */ + protected function rand($min, $max) + { + if (!is_array($this->fingerprint)) { + $this->fingerprint = array(); + } + + if ($this->useFingerprint) { + $value = current($this->fingerprint); + next($this->fingerprint); + } else { + $value = mt_rand((int)$min, (int)$max); + $this->fingerprint[] = $value; + } + + return $value; + } + + /** + * @param $x + * @param $y + * @param $nw + * @param $ne + * @param $sw + * @param $se + * + * @return int + */ + protected function interpolate($x, $y, $nw, $ne, $sw, $se) + { + list($r0, $g0, $b0) = $this->getRGB($nw); + list($r1, $g1, $b1) = $this->getRGB($ne); + list($r2, $g2, $b2) = $this->getRGB($sw); + list($r3, $g3, $b3) = $this->getRGB($se); + + $cx = 1.0 - $x; + $cy = 1.0 - $y; + + $m0 = $cx * $r0 + $x * $r1; + $m1 = $cx * $r2 + $x * $r3; + $r = (int) ($cy * $m0 + $y * $m1); + + $m0 = $cx * $g0 + $x * $g1; + $m1 = $cx * $g2 + $x * $g3; + $g = (int) ($cy * $m0 + $y * $m1); + + $m0 = $cx * $b0 + $x * $b1; + $m1 = $cx * $b2 + $x * $b3; + $b = (int) ($cy * $m0 + $y * $m1); + + return ($r << 16) | ($g << 8) | $b; + } + + /** + * @param $image + * @param $x + * @param $y + * + * @return int + */ + protected function getCol($image, $x, $y, $background) + { + $L = imagesx($image); + $H = imagesy($image); + if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) { + return $background; + } + + return imagecolorat($image, $x, $y); + } + + /** + * @param $col + * + * @return array + */ + protected function getRGB($col) + { + return array( + (int) ($col >> 16) & 0xff, + (int) ($col >> 8) & 0xff, + (int) ($col) & 0xff, + ); + } + + /** + * Validate the background image path. Return the image type if valid + * + * @param string $backgroundImage + * @return string + * @throws Exception + */ + protected function validateBackgroundImage($backgroundImage) + { + // check if file exists + if (!file_exists($backgroundImage)) { + $backgroundImageExploded = explode('/', $backgroundImage); + $imageFileName = count($backgroundImageExploded) > 1 + ? $backgroundImageExploded[count($backgroundImageExploded) - 1] + : $backgroundImage; + + throw new Exception('Invalid background image: ' . $imageFileName); + } + + // check image type + $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension + $imageType = finfo_file($finfo, $backgroundImage); + finfo_close($finfo); + + if (!in_array($imageType, $this->allowedBackgroundImageTypes)) { + throw new Exception( + 'Invalid background image type! Allowed types are: ' + . join(', ', $this->allowedBackgroundImageTypes) + ); + } + + return $imageType; + } + + /** + * Create background image from type + * + * @param string $backgroundImage + * @param string $imageType + * @return resource|\GdImage + * @throws Exception + */ + protected function createBackgroundImageFromType($backgroundImage, $imageType) + { + switch ($imageType) { + case 'image/jpeg': + $image = imagecreatefromjpeg($backgroundImage); + break; + case 'image/png': + $image = imagecreatefrompng($backgroundImage); + break; + case 'image/gif': + $image = imagecreatefromgif($backgroundImage); + break; + + default: + throw new Exception('Not supported file type for background image!'); + } + + if ($image === false) { + throw new LogicException('Failed to create background image!'); + } + + return $image; + } +} diff --git a/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilderInterface.php b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilderInterface.php new file mode 100644 index 0000000000..bebd070410 --- /dev/null +++ b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilderInterface.php @@ -0,0 +1,29 @@ + + * @author Jeremy Livingston + */ +class ImageFileHandler +{ + /** + * Name of folder for captcha images + * + * @var string + */ + protected $imageFolder; + + /** + * Absolute path to public web folder + * + * @var string + */ + protected $webPath; + + /** + * Frequency of garbage collection in fractions of 1 + * + * @var int + */ + protected $gcFreq; + + /** + * Maximum age of images in minutes + * + * @var int + */ + protected $expiration; + + /** + * @param $imageFolder + * @param $webPath + * @param $gcFreq + * @param $expiration + */ + public function __construct($imageFolder, $webPath, $gcFreq, $expiration) + { + $this->imageFolder = $imageFolder; + $this->webPath = $webPath; + $this->gcFreq = $gcFreq; + $this->expiration = $expiration; + } + + /** + * Saves the provided image content as a file + * + * @param resource|\GdImage $contents + * + * @return string + */ + public function saveAsFile($contents) + { + $this->createFolderIfMissing(); + + $filename = md5(uniqid()) . '.jpg'; + $filePath = $this->webPath . '/' . $this->imageFolder . '/' . $filename; + imagejpeg($contents, $filePath, 15); + + return '/' . $this->imageFolder . '/' . $filename; + } + + /** + * Randomly runs garbage collection on the image directory + * + * @return bool + */ + public function collectGarbage() + { + if (!mt_rand(1, $this->gcFreq) == 1) { + return false; + } + + $this->createFolderIfMissing(); + + $finder = new Finder(); + $criteria = sprintf('<= now - %s minutes', $this->expiration); + $finder->in($this->webPath . '/' . $this->imageFolder) + ->date($criteria); + + foreach ($finder->files() as $file) { + unlink($file->getPathname()); + } + + return true; + } + + /** + * Creates the folder if it doesn't exist + */ + protected function createFolderIfMissing() + { + if (!file_exists($this->webPath . '/' . $this->imageFolder)) { + mkdir($this->webPath . '/' . $this->imageFolder, 0755); + } + } +} diff --git a/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilder.php b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilder.php new file mode 100644 index 0000000000..5d79b1c476 --- /dev/null +++ b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilder.php @@ -0,0 +1,75 @@ + + */ +class PhraseBuilder implements PhraseBuilderInterface +{ + /** + * @var int + */ + public $length; + + /** + * @var string + */ + public $charset; + /** + * Constructs a PhraseBuilder with given parameters + */ + public function __construct($length = 5, $charset = 'abcdefghijklmnpqrstuvwxyz123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') + { + $this->length = $length; + $this->charset = $charset; + } + + /** + * Generates random phrase of given length with given charset + */ + public function build($length = null, $charset = null) + { + if ($length !== null) { + $this->length = $length; + } + if ($charset !== null) { + $this->charset = $charset; + } + + $phrase = ''; + $chars = str_split($this->charset); + + for ($i = 0; $i < $this->length; $i++) { + $phrase .= $chars[array_rand($chars)]; + } + + return $phrase; + } + + /** + * "Niceize" a code + */ + public function niceize($str) + { + return self::doNiceize($str); + } + + /** + * A static helper to niceize + */ + public static function doNiceize($str) + { + return strtr(strtolower($str), '01', 'ol'); + } + + /** + * A static helper to compare + */ + public static function comparePhrases($str1, $str2) + { + return self::doNiceize($str1) === self::doNiceize($str2); + } +} diff --git a/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilderInterface.php b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilderInterface.php new file mode 100644 index 0000000000..7333b6c1c6 --- /dev/null +++ b/lib/vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilderInterface.php @@ -0,0 +1,21 @@ + + */ +interface PhraseBuilderInterface +{ + /** + * Generates random phrase of given length with given charset + */ + public function build($length = null, $charset = null); + + /** + * "Niceize" a code + */ + public function niceize($str); +} diff --git a/lib/vendor/laminas/laminas-escaper/CHANGELOG.md b/lib/vendor/laminas/laminas-escaper/CHANGELOG.md new file mode 100644 index 0000000000..086e889c4d --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/CHANGELOG.md @@ -0,0 +1,73 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 2.6.1 - 2019-09-05 + +### Added + +- [zendframework/zend-escaper#32](https://github.com/zendframework/zend-escaper/pull/32) adds support for PHP 7.3. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 2.6.0 - 2018-04-25 + +### Added + +- [zendframework/zend-escaper#28](https://github.com/zendframework/zend-escaper/pull/28) adds support for PHP 7.1 and 7.2. + +### Changed + +- [zendframework/zend-escaper#25](https://github.com/zendframework/zend-escaper/pull/25) changes the behavior of the `Escaper` constructor; it now raises an + exception for non-null, non-string `$encoding` arguments. + +### Deprecated + +- Nothing. + +### Removed + +- [zendframework/zend-escaper#28](https://github.com/zendframework/zend-escaper/pull/28) removes support for PHP 5.5. + +- [zendframework/zend-escaper#28](https://github.com/zendframework/zend-escaper/pull/28) removes support for HHVM. + +### Fixed + +- Nothing. + +## 2.5.2 - 2016-06-30 + +### Added + +- [zendframework/zend-escaper#11](https://github.com/zendframework/zend-escaper/pull/11), + [zendframework/zend-escaper#12](https://github.com/zendframework/zend-escaper/pull/12), and + [zendframework/zend-escaper#13](https://github.com/zendframework/zend-escaper/pull/13) prepare and + publish documentation to https://docs.laminas.dev/laminas-escaper/ + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [zendframework/zend-escaper#3](https://github.com/zendframework/zend-escaper/pull/3) updates the + the escaping mechanism to add support for escaping characters outside the Basic + Multilingual Plane when escaping for JS, CSS, or HTML attributes. diff --git a/lib/vendor/laminas/laminas-escaper/COPYRIGHT.md b/lib/vendor/laminas/laminas-escaper/COPYRIGHT.md new file mode 100644 index 0000000000..c4fc4fee19 --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/COPYRIGHT.md @@ -0,0 +1,2 @@ +Copyright (c) 2019, Laminas Foundation. +All rights reserved. (https://getlaminas.org/) diff --git a/lib/vendor/laminas/laminas-escaper/LICENSE.md b/lib/vendor/laminas/laminas-escaper/LICENSE.md new file mode 100644 index 0000000000..09f53edc11 --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/LICENSE.md @@ -0,0 +1,27 @@ +Copyright (c) 2019, Laminas Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of Laminas Foundation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/vendor/laminas/laminas-escaper/README.md b/lib/vendor/laminas/laminas-escaper/README.md new file mode 100644 index 0000000000..a779778a73 --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/README.md @@ -0,0 +1,28 @@ +# laminas-escaper + +[![Build Status](https://travis-ci.org/laminas/laminas-escaper.svg?branch=master)](https://travis-ci.org/laminas/laminas-escaper) +[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-escaper/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-escaper?branch=master) + +The OWASP Top 10 web security risks study lists Cross-Site Scripting (XSS) in +second place. PHP’s sole functionality against XSS is limited to two functions +of which one is commonly misapplied. Thus, the laminas-escaper component was written. +It offers developers a way to escape output and defend from XSS and related +vulnerabilities by introducing contextual escaping based on peer-reviewed rules. + +## Installation + +Run the following to install this library: + +```bash +$ composer require laminas/laminas-escaper +``` + +## Documentation + +Browse the documentation online at https://docs.laminas.dev/laminas-escaper/ + +## Support + +* [Issues](https://github.com/laminas/laminas-escaper/issues/) +* [Chat](https://laminas.dev/chat/) +* [Forum](https://discourse.laminas.dev/) diff --git a/lib/vendor/laminas/laminas-escaper/composer.json b/lib/vendor/laminas/laminas-escaper/composer.json new file mode 100644 index 0000000000..c39174ff52 --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/composer.json @@ -0,0 +1,58 @@ +{ + "name": "laminas/laminas-escaper", + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "license": "BSD-3-Clause", + "keywords": [ + "laminas", + "escaper" + ], + "homepage": "https://laminas.dev", + "support": { + "docs": "https://docs.laminas.dev/laminas-escaper/", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "source": "https://github.com/laminas/laminas-escaper", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "chat": "https://laminas.dev/chat", + "forum": "https://discourse.laminas.dev" + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev", + "dev-develop": "2.7.x-dev" + } + }, + "require": { + "php": "^5.6 || ^7.0", + "laminas/laminas-zendframework-bridge": "^1.0" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2" + }, + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "LaminasTest\\Escaper\\": "test/" + } + }, + "scripts": { + "check": [ + "@cs-check", + "@test" + ], + "cs-check": "phpcs", + "cs-fix": "phpcbf", + "test": "phpunit --colors=always", + "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" + }, + "replace": { + "zendframework/zend-escaper": "self.version" + } +} diff --git a/lib/vendor/laminas/laminas-escaper/src/Escaper.php b/lib/vendor/laminas/laminas-escaper/src/Escaper.php new file mode 100644 index 0000000000..9f903a5931 --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/src/Escaper.php @@ -0,0 +1,391 @@ + 'quot', // quotation mark + 38 => 'amp', // ampersand + 60 => 'lt', // less-than sign + 62 => 'gt', // greater-than sign + ]; + + /** + * Current encoding for escaping. If not UTF-8, we convert strings from this encoding + * pre-escaping and back to this encoding post-escaping. + * + * @var string + */ + protected $encoding = 'utf-8'; + + /** + * Holds the value of the special flags passed as second parameter to + * htmlspecialchars(). + * + * @var int + */ + protected $htmlSpecialCharsFlags; + + /** + * Static Matcher which escapes characters for HTML Attribute contexts + * + * @var callable + */ + protected $htmlAttrMatcher; + + /** + * Static Matcher which escapes characters for Javascript contexts + * + * @var callable + */ + protected $jsMatcher; + + /** + * Static Matcher which escapes characters for CSS Attribute contexts + * + * @var callable + */ + protected $cssMatcher; + + /** + * List of all encoding supported by this class + * + * @var array + */ + protected $supportedEncodings = [ + 'iso-8859-1', 'iso8859-1', 'iso-8859-5', 'iso8859-5', + 'iso-8859-15', 'iso8859-15', 'utf-8', 'cp866', + 'ibm866', '866', 'cp1251', 'windows-1251', + 'win-1251', '1251', 'cp1252', 'windows-1252', + '1252', 'koi8-r', 'koi8-ru', 'koi8r', + 'big5', '950', 'gb2312', '936', + 'big5-hkscs', 'shift_jis', 'sjis', 'sjis-win', + 'cp932', '932', 'euc-jp', 'eucjp', + 'eucjp-win', 'macroman' + ]; + + /** + * Constructor: Single parameter allows setting of global encoding for use by + * the current object. + * + * @param string $encoding + * @throws Exception\InvalidArgumentException + */ + public function __construct($encoding = null) + { + if ($encoding !== null) { + if (! is_string($encoding)) { + throw new Exception\InvalidArgumentException( + get_class($this) . ' constructor parameter must be a string, received ' . gettype($encoding) + ); + } + if ($encoding === '') { + throw new Exception\InvalidArgumentException( + get_class($this) . ' constructor parameter does not allow a blank value' + ); + } + + $encoding = strtolower($encoding); + if (! in_array($encoding, $this->supportedEncodings)) { + throw new Exception\InvalidArgumentException( + 'Value of \'' . $encoding . '\' passed to ' . get_class($this) + . ' constructor parameter is invalid. Provide an encoding supported by htmlspecialchars()' + ); + } + + $this->encoding = $encoding; + } + + // We take advantage of ENT_SUBSTITUTE flag to correctly deal with invalid UTF-8 sequences. + $this->htmlSpecialCharsFlags = ENT_QUOTES | ENT_SUBSTITUTE; + + // set matcher callbacks + $this->htmlAttrMatcher = [$this, 'htmlAttrMatcher']; + $this->jsMatcher = [$this, 'jsMatcher']; + $this->cssMatcher = [$this, 'cssMatcher']; + } + + /** + * Return the encoding that all output/input is expected to be encoded in. + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Escape a string for the HTML Body context where there are very few characters + * of special meaning. Internally this will use htmlspecialchars(). + * + * @param string $string + * @return string + */ + public function escapeHtml($string) + { + return htmlspecialchars($string, $this->htmlSpecialCharsFlags, $this->encoding); + } + + /** + * Escape a string for the HTML Attribute context. We use an extended set of characters + * to escape that are not covered by htmlspecialchars() to cover cases where an attribute + * might be unquoted or quoted illegally (e.g. backticks are valid quotes for IE). + * + * @param string $string + * @return string + */ + public function escapeHtmlAttr($string) + { + $string = $this->toUtf8($string); + if ($string === '' || ctype_digit($string)) { + return $string; + } + + $result = preg_replace_callback('/[^a-z0-9,\.\-_]/iSu', $this->htmlAttrMatcher, $string); + return $this->fromUtf8($result); + } + + /** + * Escape a string for the Javascript context. This does not use json_encode(). An extended + * set of characters are escaped beyond ECMAScript's rules for Javascript literal string + * escaping in order to prevent misinterpretation of Javascript as HTML leading to the + * injection of special characters and entities. The escaping used should be tolerant + * of cases where HTML escaping was not applied on top of Javascript escaping correctly. + * Backslash escaping is not used as it still leaves the escaped character as-is and so + * is not useful in a HTML context. + * + * @param string $string + * @return string + */ + public function escapeJs($string) + { + $string = $this->toUtf8($string); + if ($string === '' || ctype_digit($string)) { + return $string; + } + + $result = preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string); + return $this->fromUtf8($result); + } + + /** + * Escape a string for the URI or Parameter contexts. This should not be used to escape + * an entire URI - only a subcomponent being inserted. The function is a simple proxy + * to rawurlencode() which now implements RFC 3986 since PHP 5.3 completely. + * + * @param string $string + * @return string + */ + public function escapeUrl($string) + { + return rawurlencode($string); + } + + /** + * Escape a string for the CSS context. CSS escaping can be applied to any string being + * inserted into CSS and escapes everything except alphanumerics. + * + * @param string $string + * @return string + */ + public function escapeCss($string) + { + $string = $this->toUtf8($string); + if ($string === '' || ctype_digit($string)) { + return $string; + } + + $result = preg_replace_callback('/[^a-z0-9]/iSu', $this->cssMatcher, $string); + return $this->fromUtf8($result); + } + + /** + * Callback function for preg_replace_callback that applies HTML Attribute + * escaping to all matches. + * + * @param array $matches + * @return string + */ + protected function htmlAttrMatcher($matches) + { + $chr = $matches[0]; + $ord = ord($chr); + + /** + * The following replaces characters undefined in HTML with the + * hex entity for the Unicode replacement character. + */ + if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") + || ($ord >= 0x7f && $ord <= 0x9f) + ) { + return '�'; + } + + /** + * Check if the current character to escape has a name entity we should + * replace it with while grabbing the integer value of the character. + */ + if (strlen($chr) > 1) { + $chr = $this->convertEncoding($chr, 'UTF-32BE', 'UTF-8'); + } + + $hex = bin2hex($chr); + $ord = hexdec($hex); + if (isset(static::$htmlNamedEntityMap[$ord])) { + return '&' . static::$htmlNamedEntityMap[$ord] . ';'; + } + + /** + * Per OWASP recommendations, we'll use upper hex entities + * for any other characters where a named entity does not exist. + */ + if ($ord > 255) { + return sprintf('&#x%04X;', $ord); + } + return sprintf('&#x%02X;', $ord); + } + + /** + * Callback function for preg_replace_callback that applies Javascript + * escaping to all matches. + * + * @param array $matches + * @return string + */ + protected function jsMatcher($matches) + { + $chr = $matches[0]; + if (strlen($chr) == 1) { + return sprintf('\\x%02X', ord($chr)); + } + $chr = $this->convertEncoding($chr, 'UTF-16BE', 'UTF-8'); + $hex = strtoupper(bin2hex($chr)); + if (strlen($hex) <= 4) { + return sprintf('\\u%04s', $hex); + } + $highSurrogate = substr($hex, 0, 4); + $lowSurrogate = substr($hex, 4, 4); + return sprintf('\\u%04s\\u%04s', $highSurrogate, $lowSurrogate); + } + + /** + * Callback function for preg_replace_callback that applies CSS + * escaping to all matches. + * + * @param array $matches + * @return string + */ + protected function cssMatcher($matches) + { + $chr = $matches[0]; + if (strlen($chr) == 1) { + $ord = ord($chr); + } else { + $chr = $this->convertEncoding($chr, 'UTF-32BE', 'UTF-8'); + $ord = hexdec(bin2hex($chr)); + } + return sprintf('\\%X ', $ord); + } + + /** + * Converts a string to UTF-8 from the base encoding. The base encoding is set via this + * class' constructor. + * + * @param string $string + * @throws Exception\RuntimeException + * @return string + */ + protected function toUtf8($string) + { + if ($this->getEncoding() === 'utf-8') { + $result = $string; + } else { + $result = $this->convertEncoding($string, 'UTF-8', $this->getEncoding()); + } + + if (! $this->isUtf8($result)) { + throw new Exception\RuntimeException( + sprintf('String to be escaped was not valid UTF-8 or could not be converted: %s', $result) + ); + } + + return $result; + } + + /** + * Converts a string from UTF-8 to the base encoding. The base encoding is set via this + * class' constructor. + * @param string $string + * @return string + */ + protected function fromUtf8($string) + { + if ($this->getEncoding() === 'utf-8') { + return $string; + } + + return $this->convertEncoding($string, $this->getEncoding(), 'UTF-8'); + } + + /** + * Checks if a given string appears to be valid UTF-8 or not. + * + * @param string $string + * @return bool + */ + protected function isUtf8($string) + { + return ($string === '' || preg_match('/^./su', $string)); + } + + /** + * Encoding conversion helper which wraps iconv and mbstring where they exist or throws + * and exception where neither is available. + * + * @param string $string + * @param string $to + * @param array|string $from + * @throws Exception\RuntimeException + * @return string + */ + protected function convertEncoding($string, $to, $from) + { + if (function_exists('iconv')) { + $result = iconv($from, $to, $string); + } elseif (function_exists('mb_convert_encoding')) { + $result = mb_convert_encoding($string, $to, $from); + } else { + throw new Exception\RuntimeException( + get_class($this) + . ' requires either the iconv or mbstring extension to be installed' + . ' when escaping for non UTF-8 strings.' + ); + } + + if ($result === false) { + return ''; // return non-fatal blank string on encoding errors from users + } + return $result; + } +} diff --git a/lib/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php b/lib/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..7ebe04ef6b --- /dev/null +++ b/lib/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php @@ -0,0 +1,13 @@ + laminas-project.flf. + +## 0.3.5 - 2019-11-06 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [#25](https://github.com/laminas/laminas-zendframework-bridge/pull/25) adds entries for ZendHttp and ZendModule, which are file name segments in files from the zend-feed and zend-config-aggregator-module packages, respectively. + +## 0.3.4 - 2019-11-06 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [#24](https://github.com/laminas/laminas-zendframework-bridge/pull/24) adds a rule to never rewrite the string `Doctrine\Zend`. + +- [#23](https://github.com/laminas/laminas-zendframework-bridge/pull/23) adds a missing map for each of ZendAcl and ZendRbac, which occur in the zend-expressive-authorization-acl and zend-expressive-authorization-rbac packages, respectively. + +## 0.3.3 - 2019-11-06 + +### Added + +- [#22](https://github.com/laminas/laminas-zendframework-bridge/pull/22) adds configuration post-processing features, exposed both as a laminas-config-aggregator post processor (for use with Expressive applications) and as a laminas-modulemanager `EVENT_MERGE_CONFIG` listener (for use with MVC applications). When registered, it will post-process the configuration, replacing known Zend Framework-specific strings with their Laminas replacements. A ruleset is provided that ensures dependency configuration is rewritten in a safe manner, routing configuration is skipped, and certain top-level configuration keys are matched exactly (instead of potentially as substrings or word stems). A later release of laminas-migration will auto-register these tools in applications when possible. + +### Changed + +- [#22](https://github.com/laminas/laminas-zendframework-bridge/pull/22) removes support for PHP versions prior to PHP 5.6. We have decided to only support supported PHP versions, whether that support is via php.net or commercial. The lowest supported PHP version we have found is 5.6. Users wishing to migrate to Laminas must at least update to PHP 5.6 before doing so. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 0.3.2 - 2019-10-30 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) removes rewriting of the Amazon library, as it is not moving to Laminas. + +- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) removes rewriting of the GCM and APNS libraries, as they are not moving to Laminas. + +### Fixed + +- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) fixes how the recaptcha and twitter library package and namespaces are rewritten. + +## 0.3.1 - 2019-04-25 + +### Added + +- [#20](https://github.com/laminas/laminas-zendframework-bridge/pull/20) provides an additional autoloader that is _prepended_ to the autoloader + stack. This new autoloader will create class aliases for interfaces, classes, + and traits referenced in type hints and class declarations, ensuring PHP is + able to resolve them correctly during class_alias operations. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 0.3.0 - 2019-04-12 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- [#16](https://github.com/laminas/laminas-zendframework-bridge/pull/16) removes the `RewriteRules::classRewrite()` method, as it is no longer + needed due to internal refactoring. + +### Fixed + +- [#16](https://github.com/laminas/laminas-zendframework-bridge/pull/16) fixes how the rewrite rules detect the word `Zend` in subnamespaces and + class names to be both more robust and simpler. + +## 0.2.5 - 2019-04-11 + +### Added + +- [#12](https://github.com/laminas/laminas-zendframework-bridge/pull/12) adds functionality for ensuring we alias namespaces and classes that + include the word `Zend` in them; e.g., `Zend\Expressive\ZendView\ZendViewRendererFactory` + will now alias to `Expressive\LaminasView\LaminasViewRendererFactory`. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 0.2.4 - 2019-04-11 + +### Added + +- [#11](https://github.com/laminas/laminas-zendframework-bridge/pull/11) adds maps for the Expressive router adapter packages. + +- [#10](https://github.com/laminas/laminas-zendframework-bridge/pull/10) adds a map for the Psr7Bridge package, as it used `Zend` within a subnamespace. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 0.2.3 - 2019-04-10 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [#9](https://github.com/laminas/laminas-zendframework-bridge/pull/9) fixes the mapping for the Problem Details package. + +## 0.2.2 - 2019-04-10 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Added a check that the discovered alias exists as a class, interface, or trait + before attempting to call `class_alias()`. + +## 0.2.1 - 2019-04-10 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [#8](https://github.com/laminas/laminas-zendframework-bridge/pull/8) fixes mappings for each of zend-expressive-authentication-zendauthentication, + zend-expressive-zendrouter, and zend-expressive-zendviewrenderer. + +## 0.2.0 - 2019-04-01 + +### Added + +- Nothing. + +### Changed + +- [#4](https://github.com/laminas/laminas-zendframework-bridge/pull/4) rewrites the autoloader to be class-based, via the class + `Laminas\ZendFrameworkBridge\Autoloader`. Additionally, the new approach + provides a performance boost by using a balanced tree algorithm, ensuring + matches occur faster. + +### Deprecated + +- Nothing. + +### Removed + +- [#4](https://github.com/laminas/laminas-zendframework-bridge/pull/4) removes function aliasing. Function aliasing will move to the packages that + provide functions. + +### Fixed + +- Nothing. + +## 0.1.0 - 2019-03-27 + +### Added + +- Adds an autoloader file that registers with `spl_autoload_register` a routine + for aliasing legacy ZF class/interface/trait names to Laminas Project + equivalents. + +- Adds autoloader files for aliasing legacy ZF package functions to Laminas + Project equivalents. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/COPYRIGHT.md b/lib/vendor/laminas/laminas-zendframework-bridge/COPYRIGHT.md new file mode 100644 index 0000000000..0a8cccc06b --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/COPYRIGHT.md @@ -0,0 +1 @@ +Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/) diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/LICENSE.md b/lib/vendor/laminas/laminas-zendframework-bridge/LICENSE.md new file mode 100644 index 0000000000..10b40f1423 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/LICENSE.md @@ -0,0 +1,26 @@ +Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of Laminas Foundation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/README.md b/lib/vendor/laminas/laminas-zendframework-bridge/README.md new file mode 100644 index 0000000000..fd7953823b --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/README.md @@ -0,0 +1,24 @@ +# laminas-zendframework-bridge + +[![Build Status](https://travis-ci.com/laminas/laminas-zendframework-bridge.svg?branch=master)](https://travis-ci.com/laminas/laminas-zendframework-bridge) +[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-zendframework-bridge/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-zendframework-bridge?branch=master) + +This library provides a custom autoloader that aliases legacy Zend Framework, +Apigility, and Expressive classes to their replacements under the Laminas +Project. + +This package should be installed only if you are also using the composer plugin +that installs Laminas packages to replace ZF/Apigility/Expressive packages. + +## Installation + +Run the following to install this library: + +```bash +$ composer require laminas/laminas-zendframework-bridge +``` + +## Support + +* [Issues](https://github.com/laminas/laminas-zendframework-bridge/issues/) +* [Forum](https://discourse.laminas.dev/) diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/composer.json b/lib/vendor/laminas/laminas-zendframework-bridge/composer.json new file mode 100644 index 0000000000..34af15a43a --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/composer.json @@ -0,0 +1,58 @@ +{ + "name": "laminas/laminas-zendframework-bridge", + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "license": "BSD-3-Clause", + "keywords": [ + "autoloading", + "laminas", + "zf", + "zendframework" + ], + "support": { + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "source": "https://github.com/laminas/laminas-zendframework-bridge", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "forum": "https://discourse.laminas.dev/" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "autoload-dev": { + "files": [ + "test/classes.php" + ], + "psr-4": { + "LaminasTest\\ZendFrameworkBridge\\": "test/", + "LaminasTest\\ZendFrameworkBridge\\TestAsset\\": "test/TestAsset/classes/", + "Laminas\\ApiTools\\": "test/TestAsset/LaminasApiTools/", + "Mezzio\\": "test/TestAsset/Mezzio/", + "Laminas\\": "test/TestAsset/Laminas/" + } + }, + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "config": { + "sort-packages": true + }, + "scripts": { + "cs-check": "phpcs", + "cs-fix": "phpcbf", + "test": "phpunit --colors=always", + "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/config/replacements.php b/lib/vendor/laminas/laminas-zendframework-bridge/config/replacements.php new file mode 100644 index 0000000000..f5344355f1 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/config/replacements.php @@ -0,0 +1,372 @@ + 'zendframework/zendframework', + 'zend-developer-tools/toolbar/bjy' => 'zend-developer-tools/toolbar/bjy', + 'zend-developer-tools/toolbar/doctrine' => 'zend-developer-tools/toolbar/doctrine', + + // NAMESPACES + // Zend Framework components + 'Zend\\AuraDi\\Config' => 'Laminas\\AuraDi\\Config', + 'Zend\\Authentication' => 'Laminas\\Authentication', + 'Zend\\Barcode' => 'Laminas\\Barcode', + 'Zend\\Cache' => 'Laminas\\Cache', + 'Zend\\Captcha' => 'Laminas\\Captcha', + 'Zend\\Code' => 'Laminas\\Code', + 'ZendCodingStandard\\Sniffs' => 'LaminasCodingStandard\\Sniffs', + 'ZendCodingStandard\\Utils' => 'LaminasCodingStandard\\Utils', + 'Zend\\ComponentInstaller' => 'Laminas\\ComponentInstaller', + 'Zend\\Config' => 'Laminas\\Config', + 'Zend\\ConfigAggregator' => 'Laminas\\ConfigAggregator', + 'Zend\\ConfigAggregatorModuleManager' => 'Laminas\\ConfigAggregatorModuleManager', + 'Zend\\ConfigAggregatorParameters' => 'Laminas\\ConfigAggregatorParameters', + 'Zend\\Console' => 'Laminas\\Console', + 'Zend\\ContainerConfigTest' => 'Laminas\\ContainerConfigTest', + 'Zend\\Crypt' => 'Laminas\\Crypt', + 'Zend\\Db' => 'Laminas\\Db', + 'ZendDeveloperTools' => 'Laminas\\DeveloperTools', + 'Zend\\Di' => 'Laminas\\Di', + 'Zend\\Diactoros' => 'Laminas\\Diactoros', + 'ZendDiagnostics\\Check' => 'Laminas\\Diagnostics\\Check', + 'ZendDiagnostics\\Result' => 'Laminas\\Diagnostics\\Result', + 'ZendDiagnostics\\Runner' => 'Laminas\\Diagnostics\\Runner', + 'Zend\\Dom' => 'Laminas\\Dom', + 'Zend\\Escaper' => 'Laminas\\Escaper', + 'Zend\\EventManager' => 'Laminas\\EventManager', + 'Zend\\Feed' => 'Laminas\\Feed', + 'Zend\\File' => 'Laminas\\File', + 'Zend\\Filter' => 'Laminas\\Filter', + 'Zend\\Form' => 'Laminas\\Form', + 'Zend\\Http' => 'Laminas\\Http', + 'Zend\\HttpHandlerRunner' => 'Laminas\\HttpHandlerRunner', + 'Zend\\Hydrator' => 'Laminas\\Hydrator', + 'Zend\\I18n' => 'Laminas\\I18n', + 'Zend\\InputFilter' => 'Laminas\\InputFilter', + 'Zend\\Json' => 'Laminas\\Json', + 'Zend\\Ldap' => 'Laminas\\Ldap', + 'Zend\\Loader' => 'Laminas\\Loader', + 'Zend\\Log' => 'Laminas\\Log', + 'Zend\\Mail' => 'Laminas\\Mail', + 'Zend\\Math' => 'Laminas\\Math', + 'Zend\\Memory' => 'Laminas\\Memory', + 'Zend\\Mime' => 'Laminas\\Mime', + 'Zend\\ModuleManager' => 'Laminas\\ModuleManager', + 'Zend\\Mvc' => 'Laminas\\Mvc', + 'Zend\\Navigation' => 'Laminas\\Navigation', + 'Zend\\Paginator' => 'Laminas\\Paginator', + 'Zend\\Permissions' => 'Laminas\\Permissions', + 'Zend\\Pimple\\Config' => 'Laminas\\Pimple\\Config', + 'Zend\\ProblemDetails' => 'Mezzio\\ProblemDetails', + 'Zend\\ProgressBar' => 'Laminas\\ProgressBar', + 'Zend\\Psr7Bridge' => 'Laminas\\Psr7Bridge', + 'Zend\\Router' => 'Laminas\\Router', + 'Zend\\Serializer' => 'Laminas\\Serializer', + 'Zend\\Server' => 'Laminas\\Server', + 'Zend\\ServiceManager' => 'Laminas\\ServiceManager', + 'ZendService\\ReCaptcha' => 'Laminas\\ReCaptcha', + 'ZendService\\Twitter' => 'Laminas\\Twitter', + 'Zend\\Session' => 'Laminas\\Session', + 'Zend\\SkeletonInstaller' => 'Laminas\\SkeletonInstaller', + 'Zend\\Soap' => 'Laminas\\Soap', + 'Zend\\Stdlib' => 'Laminas\\Stdlib', + 'Zend\\Stratigility' => 'Laminas\\Stratigility', + 'Zend\\Tag' => 'Laminas\\Tag', + 'Zend\\Test' => 'Laminas\\Test', + 'Zend\\Text' => 'Laminas\\Text', + 'Zend\\Uri' => 'Laminas\\Uri', + 'Zend\\Validator' => 'Laminas\\Validator', + 'Zend\\View' => 'Laminas\\View', + 'ZendXml' => 'Laminas\\Xml', + 'Zend\\Xml2Json' => 'Laminas\\Xml2Json', + 'Zend\\XmlRpc' => 'Laminas\\XmlRpc', + 'ZendOAuth' => 'Laminas\\OAuth', + + // class ZendAcl in zend-expressive-authorization-acl + 'ZendAcl' => 'LaminasAcl', + 'Zend\\Expressive\\Authorization\\Acl\\ZendAcl' => 'Mezzio\\Authorization\\Acl\\LaminasAcl', + // class ZendHttpClientDecorator in zend-feed + 'ZendHttp' => 'LaminasHttp', + // class ZendModuleProvider in zend-config-aggregator-modulemanager + 'ZendModule' => 'LaminasModule', + // class ZendRbac in zend-expressive-authorization-rbac + 'ZendRbac' => 'LaminasRbac', + 'Zend\\Expressive\\Authorization\\Rbac\\ZendRbac' => 'Mezzio\\Authorization\\Rbac\\LaminasRbac', + // class ZendRouter in zend-expressive-router-zendrouter + 'ZendRouter' => 'LaminasRouter', + 'Zend\\Expressive\\Router\\ZendRouter' => 'Mezzio\\Router\\LaminasRouter', + // class ZendViewRenderer in zend-expressive-zendviewrenderer + 'ZendViewRenderer' => 'LaminasViewRenderer', + 'Zend\\Expressive\\ZendView\\ZendViewRenderer' => 'Mezzio\\LaminasView\\LaminasViewRenderer', + 'a\\Zend' => 'a\\Zend', + 'b\\Zend' => 'b\\Zend', + 'c\\Zend' => 'c\\Zend', + 'd\\Zend' => 'd\\Zend', + 'e\\Zend' => 'e\\Zend', + 'f\\Zend' => 'f\\Zend', + 'g\\Zend' => 'g\\Zend', + 'h\\Zend' => 'h\\Zend', + 'i\\Zend' => 'i\\Zend', + 'j\\Zend' => 'j\\Zend', + 'k\\Zend' => 'k\\Zend', + 'l\\Zend' => 'l\\Zend', + 'm\\Zend' => 'm\\Zend', + 'n\\Zend' => 'n\\Zend', + 'o\\Zend' => 'o\\Zend', + 'p\\Zend' => 'p\\Zend', + 'q\\Zend' => 'q\\Zend', + 'r\\Zend' => 'r\\Zend', + 's\\Zend' => 's\\Zend', + 't\\Zend' => 't\\Zend', + 'u\\Zend' => 'u\\Zend', + 'v\\Zend' => 'v\\Zend', + 'w\\Zend' => 'w\\Zend', + 'x\\Zend' => 'x\\Zend', + 'y\\Zend' => 'y\\Zend', + 'z\\Zend' => 'z\\Zend', + + // Expressive + 'Zend\\Expressive' => 'Mezzio', + 'ZendAuthentication' => 'LaminasAuthentication', + 'ZendAcl' => 'LaminasAcl', + 'ZendRbac' => 'LaminasRbac', + 'ZendRouter' => 'LaminasRouter', + 'ExpressiveUrlGenerator' => 'MezzioUrlGenerator', + 'ExpressiveInstaller' => 'MezzioInstaller', + + // Apigility + 'ZF\\Apigility' => 'Laminas\\ApiTools', + 'ZF\\ApiProblem' => 'Laminas\\ApiTools\\ApiProblem', + 'ZF\\AssetManager' => 'Laminas\\ApiTools\\AssetManager', + 'ZF\\ComposerAutoloading' => 'Laminas\\ComposerAutoloading', + 'ZF\\Configuration' => 'Laminas\\ApiTools\\Configuration', + 'ZF\\ContentNegotiation' => 'Laminas\\ApiTools\\ContentNegotiation', + 'ZF\\ContentValidation' => 'Laminas\\ApiTools\\ContentValidation', + 'ZF\\DevelopmentMode' => 'Laminas\\DevelopmentMode', + 'ZF\\Doctrine\\QueryBuilder' => 'Laminas\\ApiTools\\Doctrine\\QueryBuilder', + 'ZF\\Hal' => 'Laminas\\ApiTools\\Hal', + 'ZF\\HttpCache' => 'Laminas\\ApiTools\\HttpCache', + 'ZF\\MvcAuth' => 'Laminas\\ApiTools\\MvcAuth', + 'ZF\\OAuth2' => 'Laminas\\ApiTools\\OAuth2', + 'ZF\\Rest' => 'Laminas\\ApiTools\\Rest', + 'ZF\\Rpc' => 'Laminas\\ApiTools\\Rpc', + 'ZF\\Versioning' => 'Laminas\\ApiTools\\Versioning', + 'a\\ZF' => 'a\\ZF', + 'b\\ZF' => 'b\\ZF', + 'c\\ZF' => 'c\\ZF', + 'd\\ZF' => 'd\\ZF', + 'e\\ZF' => 'e\\ZF', + 'f\\ZF' => 'f\\ZF', + 'g\\ZF' => 'g\\ZF', + 'h\\ZF' => 'h\\ZF', + 'i\\ZF' => 'i\\ZF', + 'j\\ZF' => 'j\\ZF', + 'k\\ZF' => 'k\\ZF', + 'l\\ZF' => 'l\\ZF', + 'm\\ZF' => 'm\\ZF', + 'n\\ZF' => 'n\\ZF', + 'o\\ZF' => 'o\\ZF', + 'p\\ZF' => 'p\\ZF', + 'q\\ZF' => 'q\\ZF', + 'r\\ZF' => 'r\\ZF', + 's\\ZF' => 's\\ZF', + 't\\ZF' => 't\\ZF', + 'u\\ZF' => 'u\\ZF', + 'v\\ZF' => 'v\\ZF', + 'w\\ZF' => 'w\\ZF', + 'x\\ZF' => 'x\\ZF', + 'y\\ZF' => 'y\\ZF', + 'z\\ZF' => 'z\\ZF', + + 'ApigilityModuleInterface' => 'ApiToolsModuleInterface', + 'ApigilityProviderInterface' => 'ApiToolsProviderInterface', + 'ApigilityVersionController' => 'ApiToolsVersionController', + + // PACKAGES + // ZF components, MVC + 'zendframework/skeleton-application' => 'laminas/skeleton-application', + 'zendframework/zend-auradi-config' => 'laminas/laminas-auradi-config', + 'zendframework/zend-authentication' => 'laminas/laminas-authentication', + 'zendframework/zend-barcode' => 'laminas/laminas-barcode', + 'zendframework/zend-cache' => 'laminas/laminas-cache', + 'zendframework/zend-captcha' => 'laminas/laminas-captcha', + 'zendframework/zend-code' => 'laminas/laminas-code', + 'zendframework/zend-coding-standard' => 'laminas/laminas-coding-standard', + 'zendframework/zend-component-installer' => 'laminas/laminas-component-installer', + 'zendframework/zend-composer-autoloading' => 'laminas/laminas-composer-autoloading', + 'zendframework/zend-config-aggregator' => 'laminas/laminas-config-aggregator', + 'zendframework/zend-config' => 'laminas/laminas-config', + 'zendframework/zend-console' => 'laminas/laminas-console', + 'zendframework/zend-container-config-test' => 'laminas/laminas-container-config-test', + 'zendframework/zend-crypt' => 'laminas/laminas-crypt', + 'zendframework/zend-db' => 'laminas/laminas-db', + 'zendframework/zend-developer-tools' => 'laminas/laminas-developer-tools', + 'zendframework/zend-diactoros' => 'laminas/laminas-diactoros', + 'zendframework/zenddiagnostics' => 'laminas/laminas-diagnostics', + 'zendframework/zend-di' => 'laminas/laminas-di', + 'zendframework/zend-dom' => 'laminas/laminas-dom', + 'zendframework/zend-escaper' => 'laminas/laminas-escaper', + 'zendframework/zend-eventmanager' => 'laminas/laminas-eventmanager', + 'zendframework/zend-feed' => 'laminas/laminas-feed', + 'zendframework/zend-file' => 'laminas/laminas-file', + 'zendframework/zend-filter' => 'laminas/laminas-filter', + 'zendframework/zend-form' => 'laminas/laminas-form', + 'zendframework/zend-httphandlerrunner' => 'laminas/laminas-httphandlerrunner', + 'zendframework/zend-http' => 'laminas/laminas-http', + 'zendframework/zend-hydrator' => 'laminas/laminas-hydrator', + 'zendframework/zend-i18n' => 'laminas/laminas-i18n', + 'zendframework/zend-i18n-resources' => 'laminas/laminas-i18n-resources', + 'zendframework/zend-inputfilter' => 'laminas/laminas-inputfilter', + 'zendframework/zend-json' => 'laminas/laminas-json', + 'zendframework/zend-json-server' => 'laminas/laminas-json-server', + 'zendframework/zend-ldap' => 'laminas/laminas-ldap', + 'zendframework/zend-loader' => 'laminas/laminas-loader', + 'zendframework/zend-log' => 'laminas/laminas-log', + 'zendframework/zend-mail' => 'laminas/laminas-mail', + 'zendframework/zend-math' => 'laminas/laminas-math', + 'zendframework/zend-memory' => 'laminas/laminas-memory', + 'zendframework/zend-mime' => 'laminas/laminas-mime', + 'zendframework/zend-modulemanager' => 'laminas/laminas-modulemanager', + 'zendframework/zend-mvc' => 'laminas/laminas-mvc', + 'zendframework/zend-navigation' => 'laminas/laminas-navigation', + 'zendframework/zend-oauth' => 'laminas/laminas-oauth', + 'zendframework/zend-paginator' => 'laminas/laminas-paginator', + 'zendframework/zend-permissions-acl' => 'laminas/laminas-permissions-acl', + 'zendframework/zend-permissions-rbac' => 'laminas/laminas-permissions-rbac', + 'zendframework/zend-pimple-config' => 'laminas/laminas-pimple-config', + 'zendframework/zend-progressbar' => 'laminas/laminas-progressbar', + 'zendframework/zend-psr7bridge' => 'laminas/laminas-psr7bridge', + 'zendframework/zend-recaptcha' => 'laminas/laminas-recaptcha', + 'zendframework/zend-router' => 'laminas/laminas-router', + 'zendframework/zend-serializer' => 'laminas/laminas-serializer', + 'zendframework/zend-server' => 'laminas/laminas-server', + 'zendframework/zend-servicemanager' => 'laminas/laminas-servicemanager', + 'zendframework/zendservice-recaptcha' => 'laminas/laminas-recaptcha', + 'zendframework/zendservice-twitter' => 'laminas/laminas-twitter', + 'zendframework/zend-session' => 'laminas/laminas-session', + 'zendframework/zend-skeleton-installer' => 'laminas/laminas-skeleton-installer', + 'zendframework/zend-soap' => 'laminas/laminas-soap', + 'zendframework/zend-stdlib' => 'laminas/laminas-stdlib', + 'zendframework/zend-stratigility' => 'laminas/laminas-stratigility', + 'zendframework/zend-tag' => 'laminas/laminas-tag', + 'zendframework/zend-test' => 'laminas/laminas-test', + 'zendframework/zend-text' => 'laminas/laminas-text', + 'zendframework/zend-uri' => 'laminas/laminas-uri', + 'zendframework/zend-validator' => 'laminas/laminas-validator', + 'zendframework/zend-view' => 'laminas/laminas-view', + 'zendframework/zend-xml2json' => 'laminas/laminas-xml2json', + 'zendframework/zend-xml' => 'laminas/laminas-xml', + 'zendframework/zend-xmlrpc' => 'laminas/laminas-xmlrpc', + + // Expressive packages + 'zendframework/zend-expressive' => 'mezzio/mezzio', + 'zendframework/zend-expressive-zendrouter' => 'mezzio/mezzio-laminasrouter', + 'zendframework/zend-problem-details' => 'mezzio/mezzio-problem-details', + 'zendframework/zend-expressive-zendviewrenderer' => 'mezzio/mezzio-laminasviewrenderer', + + // Apigility packages + 'zfcampus/apigility-documentation' => 'laminas-api-tools/documentation', + 'zfcampus/statuslib-example' => 'laminas-api-tools/statuslib-example', + 'zfcampus/zf-apigility' => 'laminas-api-tools/api-tools', + 'zfcampus/zf-api-problem' => 'laminas-api-tools/api-tools-api-problem', + 'zfcampus/zf-asset-manager' => 'laminas-api-tools/api-tools-asset-manager', + 'zfcampus/zf-configuration' => 'laminas-api-tools/api-tools-configuration', + 'zfcampus/zf-content-negotiation' => 'laminas-api-tools/api-tools-content-negotiation', + 'zfcampus/zf-content-validation' => 'laminas-api-tools/api-tools-content-validation', + 'zfcampus/zf-development-mode' => 'laminas/laminas-development-mode', + 'zfcampus/zf-doctrine-querybuilder' => 'laminas-api-tools/api-tools-doctrine-querybuilder', + 'zfcampus/zf-hal' => 'laminas-api-tools/api-tools-hal', + 'zfcampus/zf-http-cache' => 'laminas-api-tools/api-tools-http-cache', + 'zfcampus/zf-mvc-auth' => 'laminas-api-tools/api-tools-mvc-auth', + 'zfcampus/zf-oauth2' => 'laminas-api-tools/api-tools-oauth2', + 'zfcampus/zf-rest' => 'laminas-api-tools/api-tools-rest', + 'zfcampus/zf-rpc' => 'laminas-api-tools/api-tools-rpc', + 'zfcampus/zf-versioning' => 'laminas-api-tools/api-tools-versioning', + + // CONFIG KEYS, SCRIPT NAMES, ETC + // ZF components + '::fromZend' => '::fromLaminas', // psr7bridge + '::toZend' => '::toLaminas', // psr7bridge + 'use_zend_loader' => 'use_laminas_loader', // zend-modulemanager + 'zend-config' => 'laminas-config', + 'zend-developer-tools/' => 'laminas-developer-tools/', + 'zend-tag-cloud' => 'laminas-tag-cloud', + 'zenddevelopertools' => 'laminas-developer-tools', + 'zendbarcode' => 'laminasbarcode', + 'ZendBarcode' => 'LaminasBarcode', + 'zendcache' => 'laminascache', + 'ZendCache' => 'LaminasCache', + 'zendconfig' => 'laminasconfig', + 'ZendConfig' => 'LaminasConfig', + 'zendfeed' => 'laminasfeed', + 'ZendFeed' => 'LaminasFeed', + 'zendfilter' => 'laminasfilter', + 'ZendFilter' => 'LaminasFilter', + 'zendform' => 'laminasform', + 'ZendForm' => 'LaminasForm', + 'zendi18n' => 'laminasi18n', + 'ZendI18n' => 'LaminasI18n', + 'zendinputfilter' => 'laminasinputfilter', + 'ZendInputFilter' => 'LaminasInputFilter', + 'zendlog' => 'laminaslog', + 'ZendLog' => 'LaminasLog', + 'zendmail' => 'laminasmail', + 'ZendMail' => 'LaminasMail', + 'zendmvc' => 'laminasmvc', + 'ZendMvc' => 'LaminasMvc', + 'zendpaginator' => 'laminaspaginator', + 'ZendPaginator' => 'LaminasPaginator', + 'zendserializer' => 'laminasserializer', + 'ZendSerializer' => 'LaminasSerializer', + 'zendtag' => 'laminastag', + 'ZendTag' => 'LaminasTag', + 'zendtext' => 'laminastext', + 'ZendText' => 'LaminasText', + 'zendvalidator' => 'laminasvalidator', + 'ZendValidator' => 'LaminasValidator', + 'zendview' => 'laminasview', + 'ZendView' => 'LaminasView', + 'zend-framework.flf' => 'laminas-project.flf', + + // Expressive-related + "'zend-expressive'" => "'mezzio'", + '"zend-expressive"' => '"mezzio"', + 'zend-expressive.' => 'mezzio.', + 'zend-expressive-authorization' => 'mezzio-authorization', + 'zend-expressive-hal' => 'mezzio-hal', + 'zend-expressive-session' => 'mezzio-session', + 'zend-expressive-swoole' => 'mezzio-swoole', + 'zend-expressive-tooling' => 'mezzio-tooling', + + // Apigility-related + "'zf-apigility'" => "'api-tools'", + '"zf-apigility"' => '"api-tools"', + 'zf-apigility/' => 'api-tools/', + 'zf-apigility-admin' => 'api-tools-admin', + 'zf-content-negotiation' => 'api-tools-content-negotiation', + 'zf-hal' => 'api-tools-hal', + 'zf-rest' => 'api-tools-rest', + 'zf-rpc' => 'api-tools-rpc', + 'zf-content-validation' => 'api-tools-content-validation', + 'zf-apigility-ui' => 'api-tools-ui', + 'zf-apigility-documentation-blueprint' => 'api-tools-documentation-blueprint', + 'zf-apigility-documentation-swagger' => 'api-tools-documentation-swagger', + 'zf-apigility-welcome' => 'api-tools-welcome', + 'zf-api-problem' => 'api-tools-api-problem', + 'zf-configuration' => 'api-tools-configuration', + 'zf-http-cache' => 'api-tools-http-cache', + 'zf-mvc-auth' => 'api-tools-mvc-auth', + 'zf-oauth2' => 'api-tools-oauth2', + 'zf-versioning' => 'api-tools-versioning', + 'ZfApigilityDoctrineQueryProviderManager' => 'LaminasApiToolsDoctrineQueryProviderManager', + 'ZfApigilityDoctrineQueryCreateFilterManager' => 'LaminasApiToolsDoctrineQueryCreateFilterManager', + 'zf-apigility-doctrine' => 'api-tools-doctrine', + 'zf-development-mode' => 'laminas-development-mode', + 'zf-doctrine-querybuilder' => 'api-tools-doctrine-querybuilder', + + // 3rd party Apigility packages + 'api-skeletons/zf-' => 'api-skeletons/zf-', // api-skeletons packages + 'zf-oauth2-' => 'zf-oauth2-', // api-skeletons OAuth2-related packages + 'ZF\\OAuth2\\Client' => 'ZF\\OAuth2\\Client', // api-skeletons/zf-oauth2-client + 'ZF\\OAuth2\\Doctrine' => 'ZF\\OAuth2\\Doctrine', // api-skeletons/zf-oauth2-doctrine +]; diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php new file mode 100644 index 0000000000..6048766a27 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php @@ -0,0 +1,172 @@ +loadClass($class)) { + $legacy = $namespaces[$check] + . strtr(substr($class, strlen($check)), [ + 'ApiTools' => 'Apigility', + 'Mezzio' => 'Expressive', + 'Laminas' => 'Zend', + ]); + class_alias($class, $legacy); + } + }; + } + + /** + * @return callable + */ + private static function createAppendAutoloader(array $namespaces, ArrayObject $loaded) + { + /** + * @param string $class Class name to autoload + * @return void + */ + return static function ($class) use ($namespaces, $loaded) { + $segments = explode('\\', $class); + + if ($segments[0] === 'ZendService' && isset($segments[1])) { + $segments[0] .= '\\' . $segments[1]; + unset($segments[1]); + $segments = array_values($segments); + } + + $i = 0; + $check = ''; + + // We are checking segments of the namespace to match quicker + while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) { + $check .= $segments[$i] . '\\'; + ++$i; + } + + if ($check === '') { + return; + } + + $alias = $namespaces[$check] + . strtr(substr($class, strlen($check)), [ + 'Apigility' => 'ApiTools', + 'Expressive' => 'Mezzio', + 'Zend' => 'Laminas', + 'AbstractZendServer' => 'AbstractZendServer', + 'ZendServerDisk' => 'ZendServerDisk', + 'ZendServerShm' => 'ZendServerShm', + 'ZendMonitor' => 'ZendMonitor', + ]); + + $loaded[$alias] = true; + if (class_exists($alias) || interface_exists($alias) || trait_exists($alias)) { + class_alias($alias, $class); + } + }; + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/ConfigPostProcessor.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/ConfigPostProcessor.php new file mode 100644 index 0000000000..bac7b97479 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/ConfigPostProcessor.php @@ -0,0 +1,434 @@ + true, + 'factories' => true, + 'invokables' => true, + 'services' => true, + ]; + + /** @var array String keys => string values */ + private $exactReplacements = [ + 'zend-expressive' => 'mezzio', + 'zf-apigility' => 'api-tools', + ]; + + /** @var Replacements */ + private $replacements; + + /** @var callable[] */ + private $rulesets; + + public function __construct() + { + $this->replacements = new Replacements(); + + /* Define the rulesets for replacements. + * + * Each ruleset has the following signature: + * + * @param mixed $value + * @param string[] $keys Full nested key hierarchy leading to the value + * @return null|callable + * + * If no match is made, a null is returned, allowing it to fallback to + * the next ruleset in the list. If a match is made, a callback is returned, + * and that will be used to perform the replacement on the value. + * + * The callback should have the following signature: + * + * @param mixed $value + * @param string[] $keys + * @return mixed The transformed value + */ + $this->rulesets = [ + // Exact values + function ($value) { + return is_string($value) && isset($this->exactReplacements[$value]) + ? [$this, 'replaceExactValue'] + : null; + }, + + // Router (MVC applications) + // We do not want to rewrite these. + function ($value, array $keys) { + $key = array_pop($keys); + // Only worried about a top-level "router" key. + return $key === 'router' && count($keys) === 0 && is_array($value) + ? [$this, 'noopReplacement'] + : null; + }, + + // service- and pluginmanager handling + function ($value) { + return is_array($value) && array_intersect_key(self::SERVICE_MANAGER_KEYS_OF_INTEREST, $value) !== [] + ? [$this, 'replaceDependencyConfiguration'] + : null; + }, + + // Array values + function ($value, array $keys) { + return 0 !== count($keys) && is_array($value) + ? [$this, '__invoke'] + : null; + }, + ]; + } + + /** + * @param string[] $keys Hierarchy of keys, for determining location in + * nested configuration. + * @return array + */ + public function __invoke(array $config, array $keys = []) + { + $rewritten = []; + + foreach ($config as $key => $value) { + // Determine new key from replacements + $newKey = is_string($key) ? $this->replace($key, $keys) : $key; + + // Keep original values with original key, if the key has changed, but only at the top-level. + if (empty($keys) && $newKey !== $key) { + $rewritten[$key] = $value; + } + + // Perform value replacements, if any + $newValue = $this->replace($value, $keys, $newKey); + + // Key does not already exist and/or is not an array value + if (! array_key_exists($newKey, $rewritten) || ! is_array($rewritten[$newKey])) { + // Do not overwrite existing values with null values + $rewritten[$newKey] = array_key_exists($newKey, $rewritten) && null === $newValue + ? $rewritten[$newKey] + : $newValue; + continue; + } + + // New value is null; nothing to do. + if (null === $newValue) { + continue; + } + + // Key already exists as an array value, but $value is not an array + if (! is_array($newValue)) { + $rewritten[$newKey][] = $newValue; + continue; + } + + // Key already exists as an array value, and $value is also an array + $rewritten[$newKey] = static::merge($rewritten[$newKey], $newValue); + } + + return $rewritten; + } + + /** + * Perform substitutions as needed on an individual value. + * + * The $key is provided to allow fine-grained selection of rewrite rules. + * + * @param mixed $value + * @param string[] $keys Key hierarchy + * @param null|int|string $key + * @return mixed + */ + private function replace($value, array $keys, $key = null) + { + // Add new key to the list of keys. + // We do not need to remove it later, as we are working on a copy of the array. + array_push($keys, $key); + + // Identify rewrite strategy and perform replacements + $rewriteRule = $this->replacementRuleMatch($value, $keys); + return $rewriteRule($value, $keys); + } + + /** + * Merge two arrays together. + * + * If an integer key exists in both arrays, the value from the second array + * will be appended to the first array. If both values are arrays, they are + * merged together, else the value of the second array overwrites the one + * of the first array. + * + * Based on zend-stdlib Zend\Stdlib\ArrayUtils::merge + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * + * @return array + */ + public static function merge(array $a, array $b) + { + foreach ($b as $key => $value) { + if (! isset($a[$key]) && ! array_key_exists($key, $a)) { + $a[$key] = $value; + continue; + } + + if (null === $value && array_key_exists($key, $a)) { + // Leave as-is if value from $b is null + continue; + } + + if (is_int($key)) { + $a[] = $value; + continue; + } + + if (is_array($value) && is_array($a[$key])) { + $a[$key] = static::merge($a[$key], $value); + continue; + } + + $a[$key] = $value; + } + + return $a; + } + + /** + * @param mixed $value + * @param null|int|string $key + * @return callable Callable to invoke with value + */ + private function replacementRuleMatch($value, $key = null) + { + foreach ($this->rulesets as $ruleset) { + $result = $ruleset($value, $key); + if (is_callable($result)) { + return $result; + } + } + return [$this, 'fallbackReplacement']; + } + + /** + * Replace a value using the translation table, if the value is a string. + * + * @param mixed $value + * @return mixed + */ + private function fallbackReplacement($value) + { + return is_string($value) + ? $this->replacements->replace($value) + : $value; + } + + /** + * Replace a value matched exactly. + * + * @param mixed $value + * @return mixed + */ + private function replaceExactValue($value) + { + return $this->exactReplacements[$value]; + } + + private function replaceDependencyConfiguration(array $config) + { + $aliases = isset($config['aliases']) && is_array($config['aliases']) + ? $this->replaceDependencyAliases($config['aliases']) + : []; + + if ($aliases) { + $config['aliases'] = $aliases; + } + + $config = $this->replaceDependencyInvokables($config); + $config = $this->replaceDependencyFactories($config); + $config = $this->replaceDependencyServices($config); + + $keys = self::SERVICE_MANAGER_KEYS_OF_INTEREST; + foreach ($config as $key => $data) { + if (isset($keys[$key])) { + continue; + } + + $config[$key] = is_array($data) ? $this->__invoke($data, [$key]) : $data; + } + + return $config; + } + + /** + * Rewrite dependency aliases array + * + * In this case, we want to keep the alias as-is, but rewrite the target. + * + * We need also provide an additional alias if the alias key is a legacy class. + * + * @return array + */ + private function replaceDependencyAliases(array $aliases) + { + foreach ($aliases as $alias => $target) { + if (! is_string($alias) || ! is_string($target)) { + continue; + } + + $newTarget = $this->replacements->replace($target); + $newAlias = $this->replacements->replace($alias); + + $notIn = [$newTarget]; + $name = $newTarget; + while (isset($aliases[$name])) { + $notIn[] = $aliases[$name]; + $name = $aliases[$name]; + } + + if ($newAlias === $alias && ! in_array($alias, $notIn, true)) { + $aliases[$alias] = $newTarget; + continue; + } + + if (isset($aliases[$newAlias])) { + continue; + } + + if (! in_array($newAlias, $notIn, true)) { + $aliases[$alias] = $newAlias; + $aliases[$newAlias] = $newTarget; + } + } + + return $aliases; + } + + /** + * Rewrite dependency invokables array + * + * In this case, we want to keep the alias as-is, but rewrite the target. + * + * We need also provide an additional alias if invokable is defined with + * an alias which is a legacy class. + * + * @return array + */ + private function replaceDependencyInvokables(array $config) + { + if (empty($config['invokables']) || ! is_array($config['invokables'])) { + return $config; + } + + foreach ($config['invokables'] as $alias => $target) { + if (! is_string($alias)) { + continue; + } + + $newTarget = $this->replacements->replace($target); + $newAlias = $this->replacements->replace($alias); + + if ($alias === $target || isset($config['aliases'][$newAlias])) { + $config['invokables'][$alias] = $newTarget; + continue; + } + + $config['invokables'][$newAlias] = $newTarget; + + if ($newAlias === $alias) { + continue; + } + + $config['aliases'][$alias] = $newAlias; + + unset($config['invokables'][$alias]); + } + + return $config; + } + + /** + * @param mixed $value + * @return mixed Returns $value verbatim. + */ + private function noopReplacement($value) + { + return $value; + } + + private function replaceDependencyFactories(array $config) + { + if (empty($config['factories']) || ! is_array($config['factories'])) { + return $config; + } + + foreach ($config['factories'] as $service => $factory) { + if (! is_string($service)) { + continue; + } + + $replacedService = $this->replacements->replace($service); + $factory = is_string($factory) ? $this->replacements->replace($factory) : $factory; + $config['factories'][$replacedService] = $factory; + + if ($replacedService === $service) { + continue; + } + + unset($config['factories'][$service]); + if (isset($config['aliases'][$service])) { + continue; + } + + $config['aliases'][$service] = $replacedService; + } + + return $config; + } + + private function replaceDependencyServices(array $config) + { + if (empty($config['services']) || ! is_array($config['services'])) { + return $config; + } + + foreach ($config['services'] as $service => $serviceInstance) { + if (! is_string($service)) { + continue; + } + + $replacedService = $this->replacements->replace($service); + $serviceInstance = is_array($serviceInstance) ? $this->__invoke($serviceInstance) : $serviceInstance; + + $config['services'][$replacedService] = $serviceInstance; + + if ($service === $replacedService) { + continue; + } + + unset($config['services'][$service]); + + if (isset($config['aliases'][$service])) { + continue; + } + + $config['aliases'][$service] = $replacedService; + } + + return $config; + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/Module.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/Module.php new file mode 100644 index 0000000000..d10cb43dd8 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/Module.php @@ -0,0 +1,54 @@ +getEventManager() + ->attach('mergeConfig', [$this, 'onMergeConfig']); + } + + /** + * Perform substitutions in the merged configuration. + * + * Rewrites keys and values matching known ZF classes, namespaces, and + * configuration keys to their Laminas equivalents. + * + * Type-hinting deliberately omitted to allow unit testing + * without dependencies on packages that do not exist yet. + * + * @param ModuleEvent $event + */ + public function onMergeConfig($event) + { + /** @var ConfigMergerInterface */ + $configMerger = $event->getConfigListener(); + $processor = new ConfigPostProcessor(); + $configMerger->setMergedConfig( + $processor( + $configMerger->getMergedConfig($returnAsObject = false) + ) + ); + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/Replacements.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/Replacements.php new file mode 100644 index 0000000000..ca445c01f9 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/Replacements.php @@ -0,0 +1,46 @@ +replacements = array_merge( + require __DIR__ . '/../config/replacements.php', + $additionalReplacements + ); + + // Provide multiple variants of strings containing namespace separators + foreach ($this->replacements as $original => $replacement) { + if (false === strpos($original, '\\')) { + continue; + } + $this->replacements[str_replace('\\', '\\\\', $original)] = str_replace('\\', '\\\\', $replacement); + $this->replacements[str_replace('\\', '\\\\\\\\', $original)] = str_replace('\\', '\\\\\\\\', $replacement); + } + } + + /** + * @param string $value + * @return string + */ + public function replace($value) + { + return strtr($value, $this->replacements); + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php new file mode 100644 index 0000000000..8dc999f45e --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php @@ -0,0 +1,79 @@ + 'Mezzio\\ProblemDetails\\', + 'Zend\\Expressive\\' => 'Mezzio\\', + + // Laminas + 'Zend\\' => 'Laminas\\', + 'ZF\\ComposerAutoloading\\' => 'Laminas\\ComposerAutoloading\\', + 'ZF\\DevelopmentMode\\' => 'Laminas\\DevelopmentMode\\', + + // Apigility + 'ZF\\Apigility\\' => 'Laminas\\ApiTools\\', + 'ZF\\' => 'Laminas\\ApiTools\\', + + // ZendXml, API wrappers, zend-http OAuth support, zend-diagnostics, ZendDeveloperTools + 'ZendXml\\' => 'Laminas\\Xml\\', + 'ZendOAuth\\' => 'Laminas\\OAuth\\', + 'ZendDiagnostics\\' => 'Laminas\\Diagnostics\\', + 'ZendService\\ReCaptcha\\' => 'Laminas\\ReCaptcha\\', + 'ZendService\\Twitter\\' => 'Laminas\\Twitter\\', + 'ZendDeveloperTools\\' => 'Laminas\\DeveloperTools\\', + ]; + } + + /** + * @return array + */ + public static function namespaceReverse() + { + return [ + // ZendXml, ZendOAuth, ZendDiagnostics, ZendDeveloperTools + 'Laminas\\Xml\\' => 'ZendXml\\', + 'Laminas\\OAuth\\' => 'ZendOAuth\\', + 'Laminas\\Diagnostics\\' => 'ZendDiagnostics\\', + 'Laminas\\DeveloperTools\\' => 'ZendDeveloperTools\\', + + // Zend Service + 'Laminas\\ReCaptcha\\' => 'ZendService\\ReCaptcha\\', + 'Laminas\\Twitter\\' => 'ZendService\\Twitter\\', + + // Zend + 'Laminas\\' => 'Zend\\', + + // Expressive + 'Mezzio\\ProblemDetails\\' => 'Zend\\ProblemDetails\\', + 'Mezzio\\' => 'Zend\\Expressive\\', + + // Laminas to ZfCampus + 'Laminas\\ComposerAutoloading\\' => 'ZF\\ComposerAutoloading\\', + 'Laminas\\DevelopmentMode\\' => 'ZF\\DevelopmentMode\\', + + // Apigility + 'Laminas\\ApiTools\\Admin\\' => 'ZF\\Apigility\\Admin\\', + 'Laminas\\ApiTools\\Doctrine\\' => 'ZF\\Apigility\\Doctrine\\', + 'Laminas\\ApiTools\\Documentation\\' => 'ZF\\Apigility\\Documentation\\', + 'Laminas\\ApiTools\\Example\\' => 'ZF\\Apigility\\Example\\', + 'Laminas\\ApiTools\\Provider\\' => 'ZF\\Apigility\\Provider\\', + 'Laminas\\ApiTools\\Welcome\\' => 'ZF\\Apiglity\\Welcome\\', + 'Laminas\\ApiTools\\' => 'ZF\\', + ]; + } +} diff --git a/lib/vendor/laminas/laminas-zendframework-bridge/src/autoload.php b/lib/vendor/laminas/laminas-zendframework-bridge/src/autoload.php new file mode 100644 index 0000000000..9f2f2adf85 --- /dev/null +++ b/lib/vendor/laminas/laminas-zendframework-bridge/src/autoload.php @@ -0,0 +1,9 @@ +add($complexString2); +``` +or pass all values to the appropriate function +``` +$complexString1 = '1.23-4.56i'; +$complexString2 = '2.34+5.67i'; + +echo Complex\add($complexString1, $complexString2); +``` +If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations. + +You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object. + +## Using functions + +When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object +``` +$complexString = '1.23-4.56i'; + +$complexObject = new Complex\Complex($complexString); +echo $complexObject->sinh(); +``` +or you can call the function as you would in procedural code, passing the Complex object as an argument +``` +$complexString = '1.23-4.56i'; + +$complexObject = new Complex\Complex($complexString); +echo Complex\sinh($complexObject); +``` +When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object. +``` +$complexString = '1.23-4.56i'; + +echo Complex\sinh($complexString); +``` + +In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally + +``` +$complexString = '1.23-4.56i'; + +$complexObject = new Complex\Complex($complexString); +echo Complex\pow($complexObject, 2); +``` +or pass the additional argument when calling the method +``` +$complexString = '1.23-4.56i'; + +$complexObject = new Complex\Complex($complexString); +echo $complexObject->pow(2); +``` diff --git a/lib/vendor/markbaker/complex/classes/Autoloader.php b/lib/vendor/markbaker/complex/classes/Autoloader.php new file mode 100644 index 0000000000..792ecef0d9 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/Autoloader.php @@ -0,0 +1,53 @@ +regex = $regex; + parent::__construct($it, $regex); + } +} + +class FilenameFilter extends FilesystemRegexFilter +{ + // Filter files against the regex + public function accept() + { + return (!$this->isFile() || preg_match($this->regex, $this->getFilename())); + } +} + + +$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src'; +$srcDirectory = new RecursiveDirectoryIterator($srcFolder); + +$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i'); +$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i'); + +foreach (new RecursiveIteratorIterator($filteredFileList) as $file) { + if ($file->isFile()) { + include_once $file; + } +} diff --git a/lib/vendor/markbaker/complex/classes/src/Complex.php b/lib/vendor/markbaker/complex/classes/src/Complex.php new file mode 100644 index 0000000000..36397123c8 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/Complex.php @@ -0,0 +1,390 @@ +realPart = (float) $realPart; + $this->imaginaryPart = (float) $imaginaryPart; + $this->suffix = strtolower($suffix); + } + + /** + * Gets the real part of this complex number + * + * @return Float + */ + public function getReal() + { + return $this->realPart; + } + + /** + * Gets the imaginary part of this complex number + * + * @return Float + */ + public function getImaginary() + { + return $this->imaginaryPart; + } + + /** + * Gets the suffix of this complex number + * + * @return String + */ + public function getSuffix() + { + return $this->suffix; + } + + /** + * Returns true if this is a real value, false if a complex value + * + * @return Bool + */ + public function isReal() + { + return $this->imaginaryPart == 0.0; + } + + /** + * Returns true if this is a complex value, false if a real value + * + * @return Bool + */ + public function isComplex() + { + return !$this->isReal(); + } + + public function format() + { + $str = ""; + if ($this->imaginaryPart != 0.0) { + if (\abs($this->imaginaryPart) != 1.0) { + $str .= $this->imaginaryPart . $this->suffix; + } else { + $str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix; + } + } + if ($this->realPart != 0.0) { + if (($str) && ($this->imaginaryPart > 0.0)) { + $str = "+" . $str; + } + $str = $this->realPart . $str; + } + if (!$str) { + $str = "0.0"; + } + + return $str; + } + + public function __toString() + { + return $this->format(); + } + + /** + * Validates whether the argument is a valid complex number, converting scalar or array values if possible + * + * @param mixed $complex The value to validate + * @return Complex + * @throws Exception If the argument isn't a Complex number or cannot be converted to one + */ + public static function validateComplexArgument($complex) + { + if (is_scalar($complex) || is_array($complex)) { + $complex = new Complex($complex); + } elseif (!is_object($complex) || !($complex instanceof Complex)) { + throw new Exception('Value is not a valid complex number'); + } + + return $complex; + } + + /** + * Returns the reverse of this complex number + * + * @return Complex + */ + public function reverse() + { + return new Complex( + $this->imaginaryPart, + $this->realPart, + ($this->realPart == 0.0) ? null : $this->suffix + ); + } + + public function invertImaginary() + { + return new Complex( + $this->realPart, + $this->imaginaryPart * -1, + ($this->imaginaryPart == 0.0) ? null : $this->suffix + ); + } + + public function invertReal() + { + return new Complex( + $this->realPart * -1, + $this->imaginaryPart, + ($this->imaginaryPart == 0.0) ? null : $this->suffix + ); + } + + protected static $functions = [ + 'abs', + 'acos', + 'acosh', + 'acot', + 'acoth', + 'acsc', + 'acsch', + 'argument', + 'asec', + 'asech', + 'asin', + 'asinh', + 'atan', + 'atanh', + 'conjugate', + 'cos', + 'cosh', + 'cot', + 'coth', + 'csc', + 'csch', + 'exp', + 'inverse', + 'ln', + 'log2', + 'log10', + 'negative', + 'pow', + 'rho', + 'sec', + 'sech', + 'sin', + 'sinh', + 'sqrt', + 'tan', + 'tanh', + 'theta', + ]; + + protected static $operations = [ + 'add', + 'subtract', + 'multiply', + 'divideby', + 'divideinto', + ]; + + /** + * Returns the result of the function call or operation + * + * @return Complex|float + * @throws Exception|\InvalidArgumentException + */ + public function __call($functionName, $arguments) + { + $functionName = strtolower(str_replace('_', '', $functionName)); + + // Test for function calls + if (in_array($functionName, self::$functions, true)) { + $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}"; + return $functionName($this, ...$arguments); + } + // Test for operation calls + if (in_array($functionName, self::$operations, true)) { + $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}"; + return $functionName($this, ...$arguments); + } + throw new Exception('Function or Operation does not exist'); + } +} diff --git a/lib/vendor/markbaker/complex/classes/src/Exception.php b/lib/vendor/markbaker/complex/classes/src/Exception.php new file mode 100644 index 0000000000..a2beb732ca --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/Exception.php @@ -0,0 +1,13 @@ +getReal() - $invsqrt->getImaginary(), + $complex->getImaginary() + $invsqrt->getReal() + ); + $log = ln($adjust); + + return new Complex( + $log->getImaginary(), + -1 * $log->getReal() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/acosh.php b/lib/vendor/markbaker/complex/classes/src/functions/acosh.php new file mode 100644 index 0000000000..18a992e430 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/acosh.php @@ -0,0 +1,34 @@ +isReal() && ($complex->getReal() > 1)) { + return new Complex(\acosh($complex->getReal())); + } + + $acosh = acos($complex) + ->reverse(); + if ($acosh->getReal() < 0.0) { + $acosh = $acosh->invertReal(); + } + + return $acosh; +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/acot.php b/lib/vendor/markbaker/complex/classes/src/functions/acot.php new file mode 100644 index 0000000000..11bee4666b --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/acot.php @@ -0,0 +1,25 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return asin(inverse($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/acsch.php b/lib/vendor/markbaker/complex/classes/src/functions/acsch.php new file mode 100644 index 0000000000..bb45d34775 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/acsch.php @@ -0,0 +1,29 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return asinh(inverse($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/argument.php b/lib/vendor/markbaker/complex/classes/src/functions/argument.php new file mode 100644 index 0000000000..d7209cc484 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/argument.php @@ -0,0 +1,28 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return acos(inverse($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/asech.php b/lib/vendor/markbaker/complex/classes/src/functions/asech.php new file mode 100644 index 0000000000..b36c40e2ca --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/asech.php @@ -0,0 +1,29 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return acosh(inverse($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/asin.php b/lib/vendor/markbaker/complex/classes/src/functions/asin.php new file mode 100644 index 0000000000..9c982aca8e --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/asin.php @@ -0,0 +1,37 @@ +getReal() - $complex->getImaginary(), + $invsqrt->getImaginary() + $complex->getReal() + ); + $log = ln($adjust); + + return new Complex( + $log->getImaginary(), + -1 * $log->getReal() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/asinh.php b/lib/vendor/markbaker/complex/classes/src/functions/asinh.php new file mode 100644 index 0000000000..c1243fd7f5 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/asinh.php @@ -0,0 +1,33 @@ +isReal() && ($complex->getReal() > 1)) { + return new Complex(\asinh($complex->getReal())); + } + + $asinh = clone $complex; + $asinh = $asinh->reverse() + ->invertReal(); + $asinh = asin($asinh); + return $asinh->reverse() + ->invertImaginary(); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/atan.php b/lib/vendor/markbaker/complex/classes/src/functions/atan.php new file mode 100644 index 0000000000..2c75dcf8e4 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/atan.php @@ -0,0 +1,45 @@ +isReal()) { + return new Complex(\atan($complex->getReal())); + } + + $t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal()); + $uValue = new Complex(1, 0); + + $d1Value = clone $uValue; + $d1Value = subtract($d1Value, $t1Value); + $d2Value = add($t1Value, $uValue); + $uResult = $d1Value->divideBy($d2Value); + $uResult = ln($uResult); + + return new Complex( + (($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5, + $uResult->getReal() * 0.5, + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/atanh.php b/lib/vendor/markbaker/complex/classes/src/functions/atanh.php new file mode 100644 index 0000000000..c53f2a9a08 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/atanh.php @@ -0,0 +1,38 @@ +isReal()) { + $real = $complex->getReal(); + if ($real >= -1.0 && $real <= 1.0) { + return new Complex(\atanh($real)); + } else { + return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2)); + } + } + + $iComplex = clone $complex; + $iComplex = $iComplex->invertImaginary() + ->reverse(); + return atan($iComplex) + ->invertReal() + ->reverse(); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/conjugate.php b/lib/vendor/markbaker/complex/classes/src/functions/conjugate.php new file mode 100644 index 0000000000..bd1984b784 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/conjugate.php @@ -0,0 +1,28 @@ +getReal(), + -1 * $complex->getImaginary(), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/cos.php b/lib/vendor/markbaker/complex/classes/src/functions/cos.php new file mode 100644 index 0000000000..80a4683d59 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/cos.php @@ -0,0 +1,34 @@ +isReal()) { + return new Complex(\cos($complex->getReal())); + } + + return conjugate( + new Complex( + \cos($complex->getReal()) * \cosh($complex->getImaginary()), + \sin($complex->getReal()) * \sinh($complex->getImaginary()), + $complex->getSuffix() + ) + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/cosh.php b/lib/vendor/markbaker/complex/classes/src/functions/cosh.php new file mode 100644 index 0000000000..a4bea65369 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/cosh.php @@ -0,0 +1,32 @@ +isReal()) { + return new Complex(\cosh($complex->getReal())); + } + + return new Complex( + \cosh($complex->getReal()) * \cos($complex->getImaginary()), + \sinh($complex->getReal()) * \sin($complex->getImaginary()), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/cot.php b/lib/vendor/markbaker/complex/classes/src/functions/cot.php new file mode 100644 index 0000000000..339101e1b1 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/cot.php @@ -0,0 +1,29 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return new Complex(INF); + } + + return inverse(tan($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/coth.php b/lib/vendor/markbaker/complex/classes/src/functions/coth.php new file mode 100644 index 0000000000..7fe705a4db --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/coth.php @@ -0,0 +1,24 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return inverse(sin($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/csch.php b/lib/vendor/markbaker/complex/classes/src/functions/csch.php new file mode 100644 index 0000000000..f4500981db --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/csch.php @@ -0,0 +1,29 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return INF; + } + + return inverse(sinh($complex)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/exp.php b/lib/vendor/markbaker/complex/classes/src/functions/exp.php new file mode 100644 index 0000000000..4cac6967ec --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/exp.php @@ -0,0 +1,34 @@ +getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) { + return new Complex(-1.0, 0.0); + } + + $rho = \exp($complex->getReal()); + + return new Complex( + $rho * \cos($complex->getImaginary()), + $rho * \sin($complex->getImaginary()), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/inverse.php b/lib/vendor/markbaker/complex/classes/src/functions/inverse.php new file mode 100644 index 0000000000..7d3182adad --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/inverse.php @@ -0,0 +1,29 @@ +getReal() == 0.0 && $complex->getImaginary() == 0.0) { + throw new \InvalidArgumentException('Division by zero'); + } + + return $complex->divideInto(1.0); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/ln.php b/lib/vendor/markbaker/complex/classes/src/functions/ln.php new file mode 100644 index 0000000000..39071cf67e --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/ln.php @@ -0,0 +1,33 @@ +getReal() == 0.0) && ($complex->getImaginary() == 0.0)) { + throw new \InvalidArgumentException(); + } + + return new Complex( + \log(rho($complex)), + theta($complex), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/log10.php b/lib/vendor/markbaker/complex/classes/src/functions/log10.php new file mode 100644 index 0000000000..694d3d08ea --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/log10.php @@ -0,0 +1,32 @@ +getReal() == 0.0) && ($complex->getImaginary() == 0.0)) { + throw new \InvalidArgumentException(); + } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) { + return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix()); + } + + return ln($complex) + ->multiply(\log10(Complex::EULER)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/log2.php b/lib/vendor/markbaker/complex/classes/src/functions/log2.php new file mode 100644 index 0000000000..081f2c499f --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/log2.php @@ -0,0 +1,32 @@ +getReal() == 0.0) && ($complex->getImaginary() == 0.0)) { + throw new \InvalidArgumentException(); + } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) { + return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix()); + } + + return ln($complex) + ->multiply(\log(Complex::EULER, 2)); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/negative.php b/lib/vendor/markbaker/complex/classes/src/functions/negative.php new file mode 100644 index 0000000000..dbd11922cb --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/negative.php @@ -0,0 +1,31 @@ +getReal(), + -1 * $complex->getImaginary(), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/pow.php b/lib/vendor/markbaker/complex/classes/src/functions/pow.php new file mode 100644 index 0000000000..18ee269095 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/pow.php @@ -0,0 +1,40 @@ +getImaginary() == 0.0 && $complex->getReal() >= 0.0) { + return new Complex(\pow($complex->getReal(), $power)); + } + + $rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary())); + $rPower = \pow($rValue, $power); + $theta = $complex->argument() * $power; + if ($theta == 0) { + return new Complex(1); + } + + return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix()); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/rho.php b/lib/vendor/markbaker/complex/classes/src/functions/rho.php new file mode 100644 index 0000000000..750f3f99e2 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/rho.php @@ -0,0 +1,28 @@ +getReal() * $complex->getReal()) + + ($complex->getImaginary() * $complex->getImaginary()) + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/sec.php b/lib/vendor/markbaker/complex/classes/src/functions/sec.php new file mode 100644 index 0000000000..7dd43eaf03 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/sec.php @@ -0,0 +1,25 @@ +isReal()) { + return new Complex(\sin($complex->getReal())); + } + + return new Complex( + \sin($complex->getReal()) * \cosh($complex->getImaginary()), + \cos($complex->getReal()) * \sinh($complex->getImaginary()), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/sinh.php b/lib/vendor/markbaker/complex/classes/src/functions/sinh.php new file mode 100644 index 0000000000..4c0f6503e3 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/sinh.php @@ -0,0 +1,32 @@ +isReal()) { + return new Complex(\sinh($complex->getReal())); + } + + return new Complex( + \sinh($complex->getReal()) * \cos($complex->getImaginary()), + \cosh($complex->getReal()) * \sin($complex->getImaginary()), + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/sqrt.php b/lib/vendor/markbaker/complex/classes/src/functions/sqrt.php new file mode 100644 index 0000000000..9c171b880b --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/sqrt.php @@ -0,0 +1,29 @@ +getSuffix()); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/tan.php b/lib/vendor/markbaker/complex/classes/src/functions/tan.php new file mode 100644 index 0000000000..014d7981b4 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/tan.php @@ -0,0 +1,40 @@ +isReal()) { + return new Complex(\tan($complex->getReal())); + } + + $real = $complex->getReal(); + $imaginary = $complex->getImaginary(); + $divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2); + if ($divisor == 0.0) { + throw new \InvalidArgumentException('Division by zero'); + } + + return new Complex( + \pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor, + \pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor, + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/tanh.php b/lib/vendor/markbaker/complex/classes/src/functions/tanh.php new file mode 100644 index 0000000000..028741d6be --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/tanh.php @@ -0,0 +1,35 @@ +getReal(); + $imaginary = $complex->getImaginary(); + $divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real); + if ($divisor == 0.0) { + throw new \InvalidArgumentException('Division by zero'); + } + + return new Complex( + \sinh($real) * \cosh($real) / $divisor, + 0.5 * \sin(2 * $imaginary) / $divisor, + $complex->getSuffix() + ); +} diff --git a/lib/vendor/markbaker/complex/classes/src/functions/theta.php b/lib/vendor/markbaker/complex/classes/src/functions/theta.php new file mode 100644 index 0000000000..d12866cd83 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/functions/theta.php @@ -0,0 +1,38 @@ +getReal() == 0.0) { + if ($complex->isReal()) { + return 0.0; + } elseif ($complex->getImaginary() < 0.0) { + return M_PI / -2; + } + return M_PI / 2; + } elseif ($complex->getReal() > 0.0) { + return \atan($complex->getImaginary() / $complex->getReal()); + } elseif ($complex->getImaginary() < 0.0) { + return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal()))); + } + + return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal())); +} diff --git a/lib/vendor/markbaker/complex/classes/src/operations/add.php b/lib/vendor/markbaker/complex/classes/src/operations/add.php new file mode 100644 index 0000000000..10bd42f4f6 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/operations/add.php @@ -0,0 +1,46 @@ +isComplex() && $complex->isComplex() && + $result->getSuffix() !== $complex->getSuffix()) { + throw new Exception('Suffix Mismatch'); + } + + $real = $result->getReal() + $complex->getReal(); + $imaginary = $result->getImaginary() + $complex->getImaginary(); + + $result = new Complex( + $real, + $imaginary, + ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix()) + ); + } + + return $result; +} diff --git a/lib/vendor/markbaker/complex/classes/src/operations/divideby.php b/lib/vendor/markbaker/complex/classes/src/operations/divideby.php new file mode 100644 index 0000000000..089e0ef99e --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/operations/divideby.php @@ -0,0 +1,56 @@ +isComplex() && $complex->isComplex() && + $result->getSuffix() !== $complex->getSuffix()) { + throw new Exception('Suffix Mismatch'); + } + if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { + throw new \InvalidArgumentException('Division by zero'); + } + + $delta1 = ($result->getReal() * $complex->getReal()) + + ($result->getImaginary() * $complex->getImaginary()); + $delta2 = ($result->getImaginary() * $complex->getReal()) - + ($result->getReal() * $complex->getImaginary()); + $delta3 = ($complex->getReal() * $complex->getReal()) + + ($complex->getImaginary() * $complex->getImaginary()); + + $real = $delta1 / $delta3; + $imaginary = $delta2 / $delta3; + + $result = new Complex( + $real, + $imaginary, + ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix()) + ); + } + + return $result; +} diff --git a/lib/vendor/markbaker/complex/classes/src/operations/divideinto.php b/lib/vendor/markbaker/complex/classes/src/operations/divideinto.php new file mode 100644 index 0000000000..3dfe085e20 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/operations/divideinto.php @@ -0,0 +1,56 @@ +isComplex() && $complex->isComplex() && + $result->getSuffix() !== $complex->getSuffix()) { + throw new Exception('Suffix Mismatch'); + } + if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) { + throw new \InvalidArgumentException('Division by zero'); + } + + $delta1 = ($complex->getReal() * $result->getReal()) + + ($complex->getImaginary() * $result->getImaginary()); + $delta2 = ($complex->getImaginary() * $result->getReal()) - + ($complex->getReal() * $result->getImaginary()); + $delta3 = ($result->getReal() * $result->getReal()) + + ($result->getImaginary() * $result->getImaginary()); + + $real = $delta1 / $delta3; + $imaginary = $delta2 / $delta3; + + $result = new Complex( + $real, + $imaginary, + ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix()) + ); + } + + return $result; +} diff --git a/lib/vendor/markbaker/complex/classes/src/operations/multiply.php b/lib/vendor/markbaker/complex/classes/src/operations/multiply.php new file mode 100644 index 0000000000..bf2473ea78 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/operations/multiply.php @@ -0,0 +1,48 @@ +isComplex() && $complex->isComplex() && + $result->getSuffix() !== $complex->getSuffix()) { + throw new Exception('Suffix Mismatch'); + } + + $real = ($result->getReal() * $complex->getReal()) - + ($result->getImaginary() * $complex->getImaginary()); + $imaginary = ($result->getReal() * $complex->getImaginary()) + + ($result->getImaginary() * $complex->getReal()); + + $result = new Complex( + $real, + $imaginary, + ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix()) + ); + } + + return $result; +} diff --git a/lib/vendor/markbaker/complex/classes/src/operations/subtract.php b/lib/vendor/markbaker/complex/classes/src/operations/subtract.php new file mode 100644 index 0000000000..075ef44369 --- /dev/null +++ b/lib/vendor/markbaker/complex/classes/src/operations/subtract.php @@ -0,0 +1,46 @@ +isComplex() && $complex->isComplex() && + $result->getSuffix() !== $complex->getSuffix()) { + throw new Exception('Suffix Mismatch'); + } + + $real = $result->getReal() - $complex->getReal(); + $imaginary = $result->getImaginary() - $complex->getImaginary(); + + $result = new Complex( + $real, + $imaginary, + ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix()) + ); + } + + return $result; +} diff --git a/lib/vendor/markbaker/complex/composer.json b/lib/vendor/markbaker/complex/composer.json new file mode 100644 index 0000000000..e8a507f074 --- /dev/null +++ b/lib/vendor/markbaker/complex/composer.json @@ -0,0 +1,94 @@ +{ + "name": "markbaker/complex", + "type": "library", + "description": "PHP Class for working with complex numbers", + "keywords": ["complex", "mathematics"], + "homepage": "https://github.com/MarkBaker/PHPComplex", + "license": "MIT", + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "require": { + "php": "^5.6.0|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0", + "phpdocumentor/phpdocumentor":"2.*", + "phpmd/phpmd": "2.*", + "sebastian/phpcpd": "2.*", + "phploc/phploc": "^4.0|^5.0|^6.0|^7.0", + "squizlabs/php_codesniffer": "^3.4.0", + "phpcompatibility/php-compatibility": "^9.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0" + }, + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + }, + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "scripts": { + "style": [ + "phpcs --report-width=200 --report=summary,full -n" + ], + "mess": [ + "phpmd classes/src/ xml codesize,unusedcode,design,naming -n" + ], + "lines": [ + "phploc classes/src/ -n" + ], + "cpd": [ + "phpcpd classes/src/ -n" + ], + "versions": [ + "phpcs --report-width=200 --report=summary,full classes/src/ --standard=PHPCompatibility --runtime-set testVersion 5.6- -n" + ] + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/lib/vendor/markbaker/complex/examples/complexTest.php b/lib/vendor/markbaker/complex/examples/complexTest.php new file mode 100644 index 0000000000..7dafd8a639 --- /dev/null +++ b/lib/vendor/markbaker/complex/examples/complexTest.php @@ -0,0 +1,154 @@ +add(456); +echo $x, PHP_EOL; + +$x = new Complex(123.456); +$x->add(789.012); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->add(new Complex(-987.654, -32.1)); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->add(-987.654); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->add(new Complex(0, 1)); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->add(new Complex(0, -1)); +echo $x, PHP_EOL; + + +echo PHP_EOL, 'Subtract', PHP_EOL; + +$x = new Complex(123); +$x->subtract(456); +echo $x, PHP_EOL; + +$x = new Complex(123.456); +$x->subtract(789.012); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->subtract(new Complex(-987.654, -32.1)); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->subtract(-987.654); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->subtract(new Complex(0, 1)); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->subtract(new Complex(0, -1)); +echo $x, PHP_EOL; + + +echo PHP_EOL, 'Multiply', PHP_EOL; + +$x = new Complex(123); +$x->multiply(456); +echo $x, PHP_EOL; + +$x = new Complex(123.456); +$x->multiply(789.012); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->multiply(new Complex(-987.654, -32.1)); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->multiply(-987.654); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->multiply(new Complex(0, 1)); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->multiply(new Complex(0, -1)); +echo $x, PHP_EOL; + + +echo PHP_EOL, 'Divide By', PHP_EOL; + +$x = new Complex(123); +$x->divideBy(456); +echo $x, PHP_EOL; + +$x = new Complex(123.456); +$x->divideBy(789.012); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->divideBy(new Complex(-987.654, -32.1)); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->divideBy(-987.654); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->divideBy(new Complex(0, 1)); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->divideBy(new Complex(0, -1)); +echo $x, PHP_EOL; + + +echo PHP_EOL, 'Divide Into', PHP_EOL; + +$x = new Complex(123); +$x->divideInto(456); +echo $x, PHP_EOL; + +$x = new Complex(123.456); +$x->divideInto(789.012); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->divideInto(new Complex(-987.654, -32.1)); +echo $x, PHP_EOL; + +$x = new Complex(123.456, 78.90); +$x->divideInto(-987.654); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->divideInto(new Complex(0, 1)); +echo $x, PHP_EOL; + +$x = new Complex(-987.654, -32.1); +$x->divideInto(new Complex(0, -1)); +echo $x, PHP_EOL; diff --git a/lib/vendor/markbaker/complex/examples/testFunctions.php b/lib/vendor/markbaker/complex/examples/testFunctions.php new file mode 100644 index 0000000000..4d5ed7358b --- /dev/null +++ b/lib/vendor/markbaker/complex/examples/testFunctions.php @@ -0,0 +1,52 @@ +getMessage(), PHP_EOL; + } + } + echo PHP_EOL; + } +} diff --git a/lib/vendor/markbaker/complex/examples/testOperations.php b/lib/vendor/markbaker/complex/examples/testOperations.php new file mode 100644 index 0000000000..f791263efd --- /dev/null +++ b/lib/vendor/markbaker/complex/examples/testOperations.php @@ -0,0 +1,34 @@ + ', $result, PHP_EOL; + +echo PHP_EOL; + +echo 'Subtraction', PHP_EOL; + +$result = \Complex\subtract(...$values); +echo '=> ', $result, PHP_EOL; + +echo PHP_EOL; + +echo 'Multiplication', PHP_EOL; + +$result = \Complex\multiply(...$values); +echo '=> ', $result, PHP_EOL; diff --git a/lib/vendor/markbaker/complex/license.md b/lib/vendor/markbaker/complex/license.md new file mode 100644 index 0000000000..5b4b156196 --- /dev/null +++ b/lib/vendor/markbaker/complex/license.md @@ -0,0 +1,25 @@ +The MIT License (MIT) +===================== + +Copyright © `2017` `Mark Baker` + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/vendor/markbaker/matrix/.github/workflows/main.yaml b/lib/vendor/markbaker/matrix/.github/workflows/main.yaml new file mode 100644 index 0000000000..e7a24bb1bb --- /dev/null +++ b/lib/vendor/markbaker/matrix/.github/workflows/main.yaml @@ -0,0 +1,112 @@ +name: main +on: [ push, pull_request ] +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + php-version: + - '5.6' + - '7.0' + - '7.1' + - '7.2' + - '7.3' + - '7.4' + + name: PHP ${{ matrix.php-version }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Test with PHPUnit + run: ./vendor/bin/phpunit + + phpcs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Code style with PHP_CodeSniffer + run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr --graceful-warnings --colorize + + coverage: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: pcov + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Coverage + run: | + ./vendor/bin/phpunit --coverage-text diff --git a/lib/vendor/markbaker/matrix/README.md b/lib/vendor/markbaker/matrix/README.md new file mode 100644 index 0000000000..60cb75f9fb --- /dev/null +++ b/lib/vendor/markbaker/matrix/README.md @@ -0,0 +1,207 @@ +PHPMatrix +========== + +--- + +PHP Class for handling Matrices + +[![Build Status](https://travis-ci.org/MarkBaker/PHPMatrix.png?branch=1.2)](http://travis-ci.org/MarkBaker/PHPMatrix) + +[![Matrix Transform](https://imgs.xkcd.com/comics/matrix_transform.png)](https://xkcd.com/184/) + +Matrix Transform + +--- + +This library currently provides the following operations: + +- addition +- direct sum +- subtraction +- multiplication +- division (using [A].[B]-1) + - division by + - division into + +together with functions for + +- adjoint +- antidiagonal +- cofactors +- determinant +- diagonal +- identity +- inverse +- minors +- trace +- transpose +- solve + + Given Matrices A and B, calculate X for A.X = B + +and classes for + +- Decomposition + - LU Decomposition with partial row pivoting, + + such that [P].[A] = [L].[U] and [A] = [P]|.[L].[U] + - QR Decomposition + + such that [A] = [Q].[R] + +## TO DO + +- power() function +- Decomposition + - Cholesky Decomposition + - EigenValue Decomposition + - EigenValues + - EigenVectors + +--- + +# Usage + +To create a new Matrix object, provide an array as the constructor argument + +```php +$grid = [ + [16, 3, 2, 13], + [ 5, 10, 11, 8], + [ 9, 6, 7, 12], + [ 4, 15, 14, 1], +]; + +$matrix = new Matrix\Matrix($grid); +``` +The `Builder` class provides helper methods for creating specific matrices, specifically an identity matrix of a specified size; or a matrix of a specified dimensions, with every cell containing a set value. +```php +$matrix = Matrix\Builder::createFilledMatrix(1, 5, 3); +``` +Will create a matrix of 5 rows and 3 columns, filled with a `1` in every cell; while +```php +$matrix = Matrix\Builder::createIdentityMatrix(3); +``` +will create a 3x3 identity matrix. + + +Matrix objects are immutable: whenever you call a method or pass a grid to a function that returns a matrix value, a new Matrix object will be returned, and the original will remain unchanged. This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Matrix result). + +## Performing Mathematical Operations + +To perform mathematical operations with Matrices, you can call the appropriate method against a matrix value, passing other values as arguments + +```php +$matrix1 = new Matrix\Matrix([ + [2, 7, 6], + [9, 5, 1], + [4, 3, 8], +]); +$matrix2 = new Matrix\Matrix([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]); + +var_dump($matrix1->multiply($matrix2)->toArray()); +``` +or pass all values to the appropriate function +```php +$matrix1 = new Matrix\Matrix([ + [2, 7, 6], + [9, 5, 1], + [4, 3, 8], +]); +$matrix2 = new Matrix\Matrix([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]); + +var_dump(Matrix\multiply($matrix1, $matrix2)->toArray()); +``` +You can pass in the arguments as Matrix objects, or as arrays. + +If you want to perform the same operation against multiple values (e.g. to add three or more matrices), then you can pass multiple arguments to any of the operations. + +## Using functions + +When calling any of the available functions for a matrix value, you can either call the relevant method for the Matrix object +```php +$grid = [ + [16, 3, 2, 13], + [ 5, 10, 11, 8], + [ 9, 6, 7, 12], + [ 4, 15, 14, 1], +]; + +$matrix = new Matrix\Matrix($grid); + +echo $matrix->trace(); +``` +or you can call the function as you would in procedural code, passing the Matrix object as an argument +```php +$grid = [ + [16, 3, 2, 13], + [ 5, 10, 11, 8], + [ 9, 6, 7, 12], + [ 4, 15, 14, 1], +]; + +$matrix = new Matrix\Matrix($grid); +echo Matrix\trace($matrix); +``` +When called procedurally using the function, you can pass in the argument as a Matrix object, or as an array. +```php +$grid = [ + [16, 3, 2, 13], + [ 5, 10, 11, 8], + [ 9, 6, 7, 12], + [ 4, 15, 14, 1], +]; + +echo Matrix\trace($grid); +``` +As an alternative, it is also possible to call the method directly from the `Functions` class. +```php +$grid = [ + [16, 3, 2, 13], + [ 5, 10, 11, 8], + [ 9, 6, 7, 12], + [ 4, 15, 14, 1], +]; + +$matrix = new Matrix\Matrix($grid); +echo Matrix\Functions::trace($matrix); +``` +Used this way, methods must be called statically, and the argument must be the Matrix object, and cannot be an array. + +## Decomposition + +The library also provides classes for matrix decomposition. You can access these using +```php +$grid = [ + [1, 2], + [3, 4], +]; + +$matrix = new Matrix\Matrix($grid); + +$decomposition = new Matrix\Decomposition\QR($matrix); +$Q = $decomposition->getQ(); +$R = $decomposition->getR(); +``` + +or alternatively us the `Decomposition` factory, identifying which form of decomposition you want to use +```php +$grid = [ + [1, 2], + [3, 4], +]; + +$matrix = new Matrix\Matrix($grid); + +$decomposition = Matrix\Decomposition\Decomposition::decomposition(Matrix\Decomposition\Decomposition::QR, $matrix); +$Q = $decomposition->getQ(); +$R = $decomposition->getR(); +``` diff --git a/lib/vendor/markbaker/matrix/buildPhar.php b/lib/vendor/markbaker/matrix/buildPhar.php new file mode 100644 index 0000000000..e1b8f96fbe --- /dev/null +++ b/lib/vendor/markbaker/matrix/buildPhar.php @@ -0,0 +1,62 @@ + 'Mark Baker ', + 'Description' => 'PHP Class for working with Matrix numbers', + 'Copyright' => 'Mark Baker (c) 2013-' . date('Y'), + 'Timestamp' => time(), + 'Version' => '0.1.0', + 'Date' => date('Y-m-d') +); + +// cleanup +if (file_exists($pharName)) { + echo "Removed: {$pharName}\n"; + unlink($pharName); +} + +echo "Building phar file...\n"; + +// the phar object +$phar = new Phar($pharName, null, 'Matrix'); +$phar->buildFromDirectory($sourceDir); +$phar->setStub( +<<<'EOT' +getMessage()); + exit(1); + } + + include 'phar://functions/sqrt.php'; + + __HALT_COMPILER(); +EOT +); +$phar->setMetadata($metaData); +$phar->compressFiles(Phar::GZ); + +echo "Complete.\n"; + +exit(); diff --git a/lib/vendor/markbaker/matrix/classes/src/Builder.php b/lib/vendor/markbaker/matrix/classes/src/Builder.php new file mode 100644 index 0000000000..6bc334adcf --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Builder.php @@ -0,0 +1,70 @@ +toArray(); + + for ($x = 0; $x < $dimensions; ++$x) { + $grid[$x][$x] = 1; + } + + return new Matrix($grid); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php b/lib/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php new file mode 100644 index 0000000000..f014448758 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Decomposition/Decomposition.php @@ -0,0 +1,27 @@ +luMatrix = $matrix->toArray(); + $this->rows = $matrix->rows; + $this->columns = $matrix->columns; + + $this->buildPivot(); + } + + /** + * Get lower triangular factor. + * + * @return Matrix Lower triangular factor + */ + public function getL() + { + $lower = []; + + $columns = min($this->rows, $this->columns); + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $columns; ++$column) { + if ($row > $column) { + $lower[$row][$column] = $this->luMatrix[$row][$column]; + } elseif ($row === $column) { + $lower[$row][$column] = 1.0; + } else { + $lower[$row][$column] = 0.0; + } + } + } + + return new Matrix($lower); + } + + /** + * Get upper triangular factor. + * + * @return Matrix Upper triangular factor + */ + public function getU() + { + $upper = []; + + $rows = min($this->rows, $this->columns); + for ($row = 0; $row < $rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + if ($row <= $column) { + $upper[$row][$column] = $this->luMatrix[$row][$column]; + } else { + $upper[$row][$column] = 0.0; + } + } + } + + return new Matrix($upper); + } + + /** + * Return pivot permutation vector. + * + * @return Matrix Pivot matrix + */ + public function getP() + { + $pMatrix = []; + + $pivots = $this->pivot; + $pivotCount = count($pivots); + foreach ($pivots as $row => $pivot) { + $pMatrix[$row] = array_fill(0, $pivotCount, 0); + $pMatrix[$row][$pivot] = 1; + } + + return new Matrix($pMatrix); + } + + /** + * Return pivot permutation vector. + * + * @return array Pivot vector + */ + public function getPivot() + { + return $this->pivot; + } + + /** + * Is the matrix nonsingular? + * + * @return bool true if U, and hence A, is nonsingular + */ + public function isNonsingular() + { + for ($diagonal = 0; $diagonal < $this->columns; ++$diagonal) { + if ($this->luMatrix[$diagonal][$diagonal] === 0.0) { + return false; + } + } + + return true; + } + + private function buildPivot() + { + for ($row = 0; $row < $this->rows; ++$row) { + $this->pivot[$row] = $row; + } + + for ($column = 0; $column < $this->columns; ++$column) { + $luColumn = $this->localisedReferenceColumn($column); + + $this->applyTransformations($column, $luColumn); + + $pivot = $this->findPivot($column, $luColumn); + if ($pivot !== $column) { + $this->pivotExchange($pivot, $column); + } + + $this->computeMultipliers($column); + + unset($luColumn); + } + } + + private function localisedReferenceColumn($column) + { + $luColumn = []; + + for ($row = 0; $row < $this->rows; ++$row) { + $luColumn[$row] = &$this->luMatrix[$row][$column]; + } + + return $luColumn; + } + + private function applyTransformations($column, array $luColumn) + { + for ($row = 0; $row < $this->rows; ++$row) { + $luRow = $this->luMatrix[$row]; + // Most of the time is spent in the following dot product. + $kmax = min($row, $column); + $sValue = 0.0; + for ($kValue = 0; $kValue < $kmax; ++$kValue) { + $sValue += $luRow[$kValue] * $luColumn[$kValue]; + } + $luRow[$column] = $luColumn[$row] -= $sValue; + } + } + + private function findPivot($column, array $luColumn) + { + $pivot = $column; + for ($row = $column + 1; $row < $this->rows; ++$row) { + if (abs($luColumn[$row]) > abs($luColumn[$pivot])) { + $pivot = $row; + } + } + + return $pivot; + } + + private function pivotExchange($pivot, $column) + { + for ($kValue = 0; $kValue < $this->columns; ++$kValue) { + $tValue = $this->luMatrix[$pivot][$kValue]; + $this->luMatrix[$pivot][$kValue] = $this->luMatrix[$column][$kValue]; + $this->luMatrix[$column][$kValue] = $tValue; + } + + $lValue = $this->pivot[$pivot]; + $this->pivot[$pivot] = $this->pivot[$column]; + $this->pivot[$column] = $lValue; + } + + private function computeMultipliers($diagonal) + { + if (($diagonal < $this->rows) && ($this->luMatrix[$diagonal][$diagonal] != 0.0)) { + for ($row = $diagonal + 1; $row < $this->rows; ++$row) { + $this->luMatrix[$row][$diagonal] /= $this->luMatrix[$diagonal][$diagonal]; + } + } + } + + private function pivotB(Matrix $B) + { + $X = []; + foreach ($this->pivot as $rowId) { + $row = $B->getRows($rowId + 1)->toArray(); + $X[] = array_pop($row); + } + + return $X; + } + + /** + * Solve A*X = B. + * + * @param Matrix $B a Matrix with as many rows as A and any number of columns + * + * @throws Exception + * + * @return Matrix X so that L*U*X = B(piv,:) + */ + public function solve(Matrix $B) + { + if ($B->rows !== $this->rows) { + throw new Exception('Matrix row dimensions are not equal'); + } + + if ($this->rows !== $this->columns) { + throw new Exception('LU solve() only works on square matrices'); + } + + if (!$this->isNonsingular()) { + throw new Exception('Can only perform operation on singular matrix'); + } + + // Copy right hand side with pivoting + $nx = $B->columns; + $X = $this->pivotB($B); + + // Solve L*Y = B(piv,:) + for ($k = 0; $k < $this->columns; ++$k) { + for ($i = $k + 1; $i < $this->columns; ++$i) { + for ($j = 0; $j < $nx; ++$j) { + $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k]; + } + } + } + + // Solve U*X = Y; + for ($k = $this->columns - 1; $k >= 0; --$k) { + for ($j = 0; $j < $nx; ++$j) { + $X[$k][$j] /= $this->luMatrix[$k][$k]; + } + for ($i = 0; $i < $k; ++$i) { + for ($j = 0; $j < $nx; ++$j) { + $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k]; + } + } + } + + return new Matrix($X); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Decomposition/QR.php b/lib/vendor/markbaker/matrix/classes/src/Decomposition/QR.php new file mode 100644 index 0000000000..433281b025 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Decomposition/QR.php @@ -0,0 +1,194 @@ +qrMatrix = $matrix->toArray(); + $this->rows = $matrix->rows; + $this->columns = $matrix->columns; + + $this->decompose(); + } + + public function getHouseholdVectors() + { + $householdVectors = []; + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + if ($row >= $column) { + $householdVectors[$row][$column] = $this->qrMatrix[$row][$column]; + } else { + $householdVectors[$row][$column] = 0.0; + } + } + } + + return new Matrix($householdVectors); + } + + public function getQ() + { + $qGrid = []; + + $rowCount = $this->rows; + for ($k = $this->columns - 1; $k >= 0; --$k) { + for ($i = 0; $i < $this->rows; ++$i) { + $qGrid[$i][$k] = 0.0; + } + $qGrid[$k][$k] = 1.0; + if ($this->columns > $this->rows) { + $qGrid = array_slice($qGrid, 0, $this->rows); + } + + for ($j = $k; $j < $this->columns; ++$j) { + if (isset($this->qrMatrix[$k], $this->qrMatrix[$k][$k]) && $this->qrMatrix[$k][$k] != 0.0) { + $s = 0.0; + for ($i = $k; $i < $this->rows; ++$i) { + $s += $this->qrMatrix[$i][$k] * $qGrid[$i][$j]; + } + $s = -$s / $this->qrMatrix[$k][$k]; + for ($i = $k; $i < $this->rows; ++$i) { + $qGrid[$i][$j] += $s * $this->qrMatrix[$i][$k]; + } + } + } + } + + array_walk( + $qGrid, + function (&$row) use ($rowCount) { + $row = array_reverse($row); + $row = array_slice($row, 0, $rowCount); + } + ); + + return new Matrix($qGrid); + } + + public function getR() + { + $rGrid = []; + + for ($row = 0; $row < $this->columns; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + if ($row < $column) { + $rGrid[$row][$column] = isset($this->qrMatrix[$row][$column]) ? $this->qrMatrix[$row][$column] : 0.0; + } elseif ($row === $column) { + $rGrid[$row][$column] = isset($this->rDiagonal[$row]) ? $this->rDiagonal[$row] : 0.0; + } else { + $rGrid[$row][$column] = 0.0; + } + } + } + + if ($this->columns > $this->rows) { + $rGrid = array_slice($rGrid, 0, $this->rows); + } + + return new Matrix($rGrid); + } + + private function hypo($a, $b) + { + if (abs($a) > abs($b)) { + $r = $b / $a; + $r = abs($a) * sqrt(1 + $r * $r); + } elseif ($b != 0.0) { + $r = $a / $b; + $r = abs($b) * sqrt(1 + $r * $r); + } else { + $r = 0.0; + } + + return $r; + } + + /** + * QR Decomposition computed by Householder reflections. + */ + private function decompose() + { + for ($k = 0; $k < $this->columns; ++$k) { + // Compute 2-norm of k-th column without under/overflow. + $norm = 0.0; + for ($i = $k; $i < $this->rows; ++$i) { + $norm = $this->hypo($norm, $this->qrMatrix[$i][$k]); + } + if ($norm != 0.0) { + // Form k-th Householder vector. + if ($this->qrMatrix[$k][$k] < 0.0) { + $norm = -$norm; + } + for ($i = $k; $i < $this->rows; ++$i) { + $this->qrMatrix[$i][$k] /= $norm; + } + $this->qrMatrix[$k][$k] += 1.0; + // Apply transformation to remaining columns. + for ($j = $k + 1; $j < $this->columns; ++$j) { + $s = 0.0; + for ($i = $k; $i < $this->rows; ++$i) { + $s += $this->qrMatrix[$i][$k] * $this->qrMatrix[$i][$j]; + } + $s = -$s / $this->qrMatrix[$k][$k]; + for ($i = $k; $i < $this->rows; ++$i) { + $this->qrMatrix[$i][$j] += $s * $this->qrMatrix[$i][$k]; + } + } + } + $this->rDiagonal[$k] = -$norm; + } + } + + /** + * @return bool + */ + public function isFullRank() + { + for ($j = 0; $j < $this->columns; ++$j) { + if ($this->rDiagonal[$j] == 0.0) { + return false; + } + } + + return true; + } + + /** + * Least squares solution of A*X = B. + * + * @param Matrix $B a Matrix with as many rows as A and any number of columns + * + * @throws Exception + * + * @return Matrix matrix that minimizes the two norm of Q*R*X-B + */ + public function solve(Matrix $B) + { + if ($B->rows !== $this->rows) { + throw new Exception('Matrix row dimensions are not equal'); + } + + if (!$this->isFullRank()) { + throw new Exception('Can only perform this operation on a full-rank matrix'); + } + + // Compute Y = transpose(Q)*B + $Y = $this->getQ()->transpose() + ->multiply($B); + // Solve R*X = Y; + return $this->getR()->inverse() + ->multiply($Y); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Exception.php b/lib/vendor/markbaker/matrix/classes/src/Exception.php new file mode 100644 index 0000000000..55a428ca5a --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Exception.php @@ -0,0 +1,13 @@ +isSquare()) { + throw new Exception('Adjoint can only be calculated for a square matrix'); + } + + return self::getAdjoint($matrix); + } + + /** + * Calculate the cofactors of the matrix + * + * @param Matrix $matrix The matrix whose cofactors we wish to calculate + * @return Matrix + * + * @throws Exception + */ + private static function getCofactors(Matrix $matrix) + { + $cofactors = self::getMinors($matrix); + $dimensions = $matrix->rows; + + $cof = 1; + for ($i = 0; $i < $dimensions; ++$i) { + $cofs = $cof; + for ($j = 0; $j < $dimensions; ++$j) { + $cofactors[$i][$j] *= $cofs; + $cofs = -$cofs; + } + $cof = -$cof; + } + + return new Matrix($cofactors); + } + + /** + * Return the cofactors of this matrix + * + * @param Matrix $matrix The matrix whose cofactors we wish to calculate + * @return Matrix + * + * @throws Exception + */ + public static function cofactors(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Cofactors can only be calculated for a square matrix'); + } + + return self::getCofactors($matrix); + } + + /** + * @param Matrix $matrix + * @param int $row + * @param int $column + * @return float + * @throws Exception + */ + private static function getDeterminantSegment(Matrix $matrix, $row, $column) + { + $tmpMatrix = $matrix->toArray(); + unset($tmpMatrix[$row]); + array_walk( + $tmpMatrix, + function (&$row) use ($column) { + unset($row[$column]); + } + ); + + return self::getDeterminant(new Matrix($tmpMatrix)); + } + + /** + * Calculate the determinant of the matrix + * + * @param Matrix $matrix The matrix whose determinant we wish to calculate + * @return float + * + * @throws Exception + */ + private static function getDeterminant(Matrix $matrix) + { + $dimensions = $matrix->rows; + $determinant = 0; + + switch ($dimensions) { + case 1: + $determinant = $matrix->getValue(1, 1); + break; + case 2: + $determinant = $matrix->getValue(1, 1) * $matrix->getValue(2, 2) - + $matrix->getValue(1, 2) * $matrix->getValue(2, 1); + break; + default: + for ($i = 1; $i <= $dimensions; ++$i) { + $det = $matrix->getValue(1, $i) * self::getDeterminantSegment($matrix, 0, $i - 1); + if (($i % 2) == 0) { + $determinant -= $det; + } else { + $determinant += $det; + } + } + break; + } + + return $determinant; + } + + /** + * Return the determinant of this matrix + * + * @param Matrix $matrix The matrix whose determinant we wish to calculate + * @return float + * @throws Exception + **/ + public static function determinant(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Determinant can only be calculated for a square matrix'); + } + + return self::getDeterminant($matrix); + } + + /** + * Return the diagonal of this matrix + * + * @param Matrix $matrix The matrix whose diagonal we wish to calculate + * @return Matrix + * @throws Exception + **/ + public static function diagonal(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Diagonal can only be extracted from a square matrix'); + } + + $dimensions = $matrix->rows; + $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions) + ->toArray(); + + for ($i = 0; $i < $dimensions; ++$i) { + $grid[$i][$i] = $matrix->getValue($i + 1, $i + 1); + } + + return new Matrix($grid); + } + + /** + * Return the antidiagonal of this matrix + * + * @param Matrix $matrix The matrix whose antidiagonal we wish to calculate + * @return Matrix + * @throws Exception + **/ + public static function antidiagonal(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Anti-Diagonal can only be extracted from a square matrix'); + } + + $dimensions = $matrix->rows; + $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions) + ->toArray(); + + for ($i = 0; $i < $dimensions; ++$i) { + $grid[$i][$dimensions - $i - 1] = $matrix->getValue($i + 1, $dimensions - $i); + } + + return new Matrix($grid); + } + + /** + * Return the identity matrix + * The identity matrix, or sometimes ambiguously called a unit matrix, of size n is the n × n square matrix + * with ones on the main diagonal and zeros elsewhere + * + * @param Matrix $matrix The matrix whose identity we wish to calculate + * @return Matrix + * @throws Exception + **/ + public static function identity(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Identity can only be created for a square matrix'); + } + + $dimensions = $matrix->rows; + + return Builder::createIdentityMatrix($dimensions); + } + + /** + * Return the inverse of this matrix + * + * @param Matrix $matrix The matrix whose inverse we wish to calculate + * @return Matrix + * @throws Exception + **/ + public static function inverse(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Inverse can only be calculated for a square matrix'); + } + + $determinant = self::getDeterminant($matrix); + if ($determinant == 0.0) { + throw new Exception('Inverse can only be calculated for a matrix with a non-zero determinant'); + } + + if ($matrix->rows == 1) { + return new Matrix([[1 / $matrix->getValue(1, 1)]]); + } + + return self::getAdjoint($matrix) + ->multiply(1 / $determinant); + } + + /** + * Calculate the minors of the matrix + * + * @param Matrix $matrix The matrix whose minors we wish to calculate + * @return array[] + * + * @throws Exception + */ + protected static function getMinors(Matrix $matrix) + { + $minors = $matrix->toArray(); + $dimensions = $matrix->rows; + if ($dimensions == 1) { + return $minors; + } + + for ($i = 0; $i < $dimensions; ++$i) { + for ($j = 0; $j < $dimensions; ++$j) { + $minors[$i][$j] = self::getDeterminantSegment($matrix, $i, $j); + } + } + + return $minors; + } + + /** + * Return the minors of the matrix + * The minor of a matrix A is the determinant of some smaller square matrix, cut down from A by removing one or + * more of its rows or columns. + * Minors obtained by removing just one row and one column from square matrices (first minors) are required for + * calculating matrix cofactors, which in turn are useful for computing both the determinant and inverse of + * square matrices. + * + * @param Matrix $matrix The matrix whose minors we wish to calculate + * @return Matrix + * @throws Exception + **/ + public static function minors(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Minors can only be calculated for a square matrix'); + } + + return new Matrix(self::getMinors($matrix)); + } + + /** + * Return the trace of this matrix + * The trace is defined as the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right) + * of the matrix + * + * @param Matrix $matrix The matrix whose trace we wish to calculate + * @return float + * @throws Exception + **/ + public static function trace(Matrix $matrix) + { + if (!$matrix->isSquare()) { + throw new Exception('Trace can only be extracted from a square matrix'); + } + + $dimensions = $matrix->rows; + $result = 0; + for ($i = 1; $i <= $dimensions; ++$i) { + $result += $matrix->getValue($i, $i); + } + + return $result; + } + + /** + * Return the transpose of this matrix + * + * @param Matrix $matrix The matrix whose transpose we wish to calculate + * @return Matrix + **/ + public static function transpose(Matrix $matrix) + { + $array = array_values(array_merge([null], $matrix->toArray())); + $grid = call_user_func_array( + 'array_map', + $array + ); + + return new Matrix($grid); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Functions/adjoint.php b/lib/vendor/markbaker/matrix/classes/src/Functions/adjoint.php new file mode 100644 index 0000000000..fc1e16995c --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Functions/adjoint.php @@ -0,0 +1,30 @@ +buildFromArray(array_values($grid)); + } + + /* + * Create a new Matrix object from an array of values + * + * @param array $grid + */ + protected function buildFromArray(array $grid) + { + $this->rows = count($grid); + $columns = array_reduce( + $grid, + function ($carry, $value) { + return max($carry, is_array($value) ? count($value) : 1); + } + ); + $this->columns = $columns; + + array_walk( + $grid, + function (&$value) use ($columns) { + if (!is_array($value)) { + $value = [$value]; + } + $value = array_pad(array_values($value), $columns, null); + } + ); + + $this->grid = $grid; + } + + /** + * Validate that a row number is a positive integer + * + * @param int $row + * @return int + * @throws Exception + */ + public static function validateRow($row) + { + if ((!is_numeric($row)) || (intval($row) < 1)) { + throw new Exception('Invalid Row'); + } + + return (int)$row; + } + + /** + * Validate that a column number is a positive integer + * + * @param int $column + * @return int + * @throws Exception + */ + public static function validateColumn($column) + { + if ((!is_numeric($column)) || (intval($column) < 1)) { + throw new Exception('Invalid Column'); + } + + return (int)$column; + } + + /** + * Validate that a row number falls within the set of rows for this matrix + * + * @param int $row + * @return int + * @throws Exception + */ + protected function validateRowInRange($row) + { + $row = static::validateRow($row); + if ($row > $this->rows) { + throw new Exception('Requested Row exceeds matrix size'); + } + + return $row; + } + + /** + * Validate that a column number falls within the set of columns for this matrix + * + * @param int $column + * @return int + * @throws Exception + */ + protected function validateColumnInRange($column) + { + $column = static::validateColumn($column); + if ($column > $this->columns) { + throw new Exception('Requested Column exceeds matrix size'); + } + + return $column; + } + + /** + * Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows + * A $rowCount value of 0 will return all rows of the matrix from $row + * A negative $rowCount value will return rows until that many rows from the end of the matrix + * + * Note that row numbers start from 1, not from 0 + * + * @param int $row + * @param int $rowCount + * @return static + * @throws Exception + */ + public function getRows($row, $rowCount = 1) + { + $row = $this->validateRowInRange($row); + if ($rowCount === 0) { + $rowCount = $this->rows - $row + 1; + } + + return new static(array_slice($this->grid, $row - 1, (int)$rowCount)); + } + + /** + * Return a new matrix as a subset of columns from this matrix, starting at column number $column, and $columnCount columns + * A $columnCount value of 0 will return all columns of the matrix from $column + * A negative $columnCount value will return columns until that many columns from the end of the matrix + * + * Note that column numbers start from 1, not from 0 + * + * @param int $column + * @param int $columnCount + * @return Matrix + * @throws Exception + */ + public function getColumns($column, $columnCount = 1) + { + $column = $this->validateColumnInRange($column); + if ($columnCount < 1) { + $columnCount = $this->columns + $columnCount - $column + 1; + } + + $grid = []; + for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) { + $grid[] = array_column($this->grid, $i); + } + + return (new static($grid))->transpose(); + } + + /** + * Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row, + * and $rowCount rows + * A negative $rowCount value will drop rows until that many rows from the end of the matrix + * A $rowCount value of 0 will remove all rows of the matrix from $row + * + * Note that row numbers start from 1, not from 0 + * + * @param int $row + * @param int $rowCount + * @return static + * @throws Exception + */ + public function dropRows($row, $rowCount = 1) + { + $this->validateRowInRange($row); + if ($rowCount === 0) { + $rowCount = $this->rows - $row + 1; + } + + $grid = $this->grid; + array_splice($grid, $row - 1, (int)$rowCount); + + return new static($grid); + } + + /** + * Return a new matrix as a subset of columns from this matrix, dropping columns starting at column number $column, + * and $columnCount columns + * A negative $columnCount value will drop columns until that many columns from the end of the matrix + * A $columnCount value of 0 will remove all columns of the matrix from $column + * + * Note that column numbers start from 1, not from 0 + * + * @param int $column + * @param int $columnCount + * @return static + * @throws Exception + */ + public function dropColumns($column, $columnCount = 1) + { + $this->validateColumnInRange($column); + if ($columnCount < 1) { + $columnCount = $this->columns + $columnCount - $column + 1; + } + + $grid = $this->grid; + array_walk( + $grid, + function (&$row) use ($column, $columnCount) { + array_splice($row, $column - 1, (int)$columnCount); + } + ); + + return new static($grid); + } + + /** + * Return a value from this matrix, from the "cell" identified by the row and column numbers + * Note that row and column numbers start from 1, not from 0 + * + * @param int $row + * @param int $column + * @return mixed + * @throws Exception + */ + public function getValue($row, $column) + { + $row = $this->validateRowInRange($row); + $column = $this->validateColumnInRange($column); + + return $this->grid[$row - 1][$column - 1]; + } + + /** + * Returns a Generator that will yield each row of the matrix in turn as a vector matrix + * or the value of each cell if the matrix is a column vector + * + * @return Generator|Matrix[]|mixed[] + */ + public function rows() + { + foreach ($this->grid as $i => $row) { + yield $i + 1 => ($this->columns == 1) + ? $row[0] + : new static([$row]); + } + } + + /** + * Returns a Generator that will yield each column of the matrix in turn as a vector matrix + * or the value of each cell if the matrix is a row vector + * + * @return Generator|Matrix[]|mixed[] + */ + public function columns() + { + for ($i = 0; $i < $this->columns; ++$i) { + yield $i + 1 => ($this->rows == 1) + ? $this->grid[0][$i] + : new static(array_column($this->grid, $i)); + } + } + + /** + * Identify if the row and column dimensions of this matrix are equal, + * i.e. if it is a "square" matrix + * + * @return bool + */ + public function isSquare() + { + return $this->rows == $this->columns; + } + + /** + * Identify if this matrix is a vector + * i.e. if it comprises only a single row or a single column + * + * @return bool + */ + public function isVector() + { + return $this->rows == 1 || $this->columns == 1; + } + + /** + * Return the matrix as a 2-dimensional array + * + * @return array + */ + public function toArray() + { + return $this->grid; + } + + /** + * Solve A*X = B. + * + * @param Matrix $B Right hand side + * + * @throws Exception + * + * @return Matrix ... Solution if A is square, least squares solution otherwise + */ + public function solve(Matrix $B) + { + if ($this->columns === $this->rows) { + return (new LU($this))->solve($B); + } + + return (new QR($this))->solve($B); + } + + protected static $getters = [ + 'rows', + 'columns', + ]; + + /** + * Access specific properties as read-only (no setters) + * + * @param string $propertyName + * @return mixed + * @throws Exception + */ + public function __get($propertyName) + { + $propertyName = strtolower($propertyName); + + // Test for function calls + if (in_array($propertyName, self::$getters)) { + return $this->$propertyName; + } + + throw new Exception('Property does not exist'); + } + + protected static $functions = [ + 'antidiagonal', + 'adjoint', + 'cofactors', + 'determinant', + 'diagonal', + 'identity', + 'inverse', + 'minors', + 'trace', + 'transpose', + ]; + + protected static $operations = [ + 'add', + 'subtract', + 'multiply', + 'divideby', + 'divideinto', + 'directsum', + ]; + + /** + * Returns the result of the function call or operation + * + * @param string $functionName + * @param mixed[] $arguments + * @return Matrix|float + * @throws Exception + */ + public function __call($functionName, $arguments) + { + $functionName = strtolower(str_replace('_', '', $functionName)); + + if (in_array($functionName, self::$functions, true) || in_array($functionName, self::$operations, true)) { + $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}"; + if (is_callable($functionName)) { + $arguments = array_values(array_merge([$this], $arguments)); + return call_user_func_array($functionName, $arguments); + } + } + throw new Exception('Function or Operation does not exist'); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/add.php b/lib/vendor/markbaker/matrix/classes/src/Operations/add.php new file mode 100644 index 0000000000..4ae731221a --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/add.php @@ -0,0 +1,44 @@ + $matrixValues The matrices to add + * @return Matrix + * @throws Exception + */ +function add(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('Addition operation requires at least 2 arguments'); + } + + $matrix = array_shift($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('Addition arguments must be Matrix or array'); + } + + $result = new Addition($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/directsum.php b/lib/vendor/markbaker/matrix/classes/src/Operations/directsum.php new file mode 100644 index 0000000000..9d15b89bb7 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/directsum.php @@ -0,0 +1,44 @@ + $matrixValues The matrices to add + * @return Matrix + * @throws Exception + */ +function directsum(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('DirectSum operation requires at least 2 arguments'); + } + + $matrix = array_shift($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('DirectSum arguments must be Matrix or array'); + } + + $result = new DirectSum($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/divideby.php b/lib/vendor/markbaker/matrix/classes/src/Operations/divideby.php new file mode 100644 index 0000000000..767d03a5af --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/divideby.php @@ -0,0 +1,44 @@ + $matrixValues The matrices to divide + * @return Matrix + * @throws Exception + */ +function divideby(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('Division operation requires at least 2 arguments'); + } + + $matrix = array_shift($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('Division arguments must be Matrix or array'); + } + + $result = new Division($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/divideinto.php b/lib/vendor/markbaker/matrix/classes/src/Operations/divideinto.php new file mode 100644 index 0000000000..c6ce63312e --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/divideinto.php @@ -0,0 +1,45 @@ + $matrixValues The numbers to divide + * @return Matrix + * @throws Exception + */ +function divideinto(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('Division operation requires at least 2 arguments'); + } + + $matrix = array_pop($matrixValues); + $matrixValues = array_reverse($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('Division arguments must be Matrix or array'); + } + + $result = new Division($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/multiply.php b/lib/vendor/markbaker/matrix/classes/src/Operations/multiply.php new file mode 100644 index 0000000000..1428f091fb --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/multiply.php @@ -0,0 +1,44 @@ + $matrixValues The matrices to multiply + * @return Matrix + * @throws Exception + */ +function multiply(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('Multiplication operation requires at least 2 arguments'); + } + + $matrix = array_shift($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('Multiplication arguments must be Matrix or array'); + } + + $result = new Multiplication($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operations/subtract.php b/lib/vendor/markbaker/matrix/classes/src/Operations/subtract.php new file mode 100644 index 0000000000..3123b61ec8 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operations/subtract.php @@ -0,0 +1,44 @@ + $matrixValues The matrices to subtract + * @return Matrix + * @throws Exception + */ +function subtract(...$matrixValues) +{ + if (count($matrixValues) < 2) { + throw new Exception('Subtraction operation requires at least 2 arguments'); + } + + $matrix = array_shift($matrixValues); + + if (is_array($matrix)) { + $matrix = new Matrix($matrix); + } + if (!$matrix instanceof Matrix) { + throw new Exception('Subtraction arguments must be Matrix or array'); + } + + $result = new Subtraction($matrix); + + foreach ($matrixValues as $matrix) { + $result->execute($matrix); + } + + return $result->result(); +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/Addition.php b/lib/vendor/markbaker/matrix/classes/src/Operators/Addition.php new file mode 100644 index 0000000000..e78c6d7d90 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/Addition.php @@ -0,0 +1,68 @@ +addMatrix($value); + } elseif (is_numeric($value)) { + return $this->addScalar($value); + } + + throw new Exception('Invalid argument for addition'); + } + + /** + * Execute the addition for a scalar + * + * @param mixed $value The numeric value to add to the current base value + * @return $this The operation object, allowing multiple additions to be chained + **/ + protected function addScalar($value) + { + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + $this->matrix[$row][$column] += $value; + } + } + + return $this; + } + + /** + * Execute the addition for a matrix + * + * @param Matrix $value The numeric value to add to the current base value + * @return $this The operation object, allowing multiple additions to be chained + * @throws Exception If the provided argument is not appropriate for the operation + **/ + protected function addMatrix(Matrix $value) + { + $this->validateMatchingDimensions($value); + + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + $this->matrix[$row][$column] += $value->getValue($row + 1, $column + 1); + } + } + + return $this; + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php b/lib/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php new file mode 100644 index 0000000000..6db0853bf1 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/DirectSum.php @@ -0,0 +1,64 @@ +directSumMatrix($value); + } + + throw new Exception('Invalid argument for addition'); + } + + /** + * Execute the direct sum for a matrix + * + * @param Matrix $value The numeric value to concatenate/direct sum with the current base value + * @return $this The operation object, allowing multiple additions to be chained + **/ + private function directSumMatrix($value) + { + $originalColumnCount = count($this->matrix[0]); + $originalRowCount = count($this->matrix); + $valColumnCount = $value->columns; + $valRowCount = $value->rows; + $value = $value->toArray(); + + for ($row = 0; $row < $this->rows; ++$row) { + $this->matrix[$row] = array_merge($this->matrix[$row], array_fill(0, $valColumnCount, 0)); + } + + $this->matrix = array_merge( + $this->matrix, + array_fill(0, $valRowCount, array_fill(0, $originalColumnCount, 0)) + ); + + for ($row = $originalRowCount; $row < $originalRowCount + $valRowCount; ++$row) { + array_splice( + $this->matrix[$row], + $originalColumnCount, + $valColumnCount, + $value[$row - $originalRowCount] + ); + } + + return $this; + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/Division.php b/lib/vendor/markbaker/matrix/classes/src/Operators/Division.php new file mode 100644 index 0000000000..2a573f5500 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/Division.php @@ -0,0 +1,38 @@ +multiplyMatrix($value); + } elseif (is_numeric($value)) { + return $this->multiplyScalar(1 / $value); + } + + throw new Exception('Invalid argument for division'); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php b/lib/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php new file mode 100644 index 0000000000..63df162d6b --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/Multiplication.php @@ -0,0 +1,77 @@ +multiplyMatrix($value); + } elseif (is_numeric($value)) { + return $this->multiplyScalar($value); + } + + throw new Exception('Invalid argument for multiplication'); + } + + /** + * Execute the multiplication for a scalar + * + * @param mixed $value The numeric value to multiply with the current base value + * @return $this The operation object, allowing multiple mutiplications to be chained + **/ + protected function multiplyScalar($value) + { + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + $this->matrix[$row][$column] *= $value; + } + } + + return $this; + } + + /** + * Execute the multiplication for a matrix + * + * @param Matrix $value The numeric value to multiply with the current base value + * @return $this The operation object, allowing multiple mutiplications to be chained + * @throws Exception If the provided argument is not appropriate for the operation + **/ + protected function multiplyMatrix(Matrix $value) + { + $this->validateReflectingDimensions($value); + + $newRows = $this->rows; + $newColumns = $value->columns; + $matrix = Builder::createFilledMatrix(0, $newRows, $newColumns) + ->toArray(); + for ($row = 0; $row < $newRows; ++$row) { + for ($column = 0; $column < $newColumns; ++$column) { + $columnData = $value->getColumns($column + 1)->toArray(); + foreach ($this->matrix[$row] as $key => $valueData) { + $matrix[$row][$column] += $valueData * $columnData[$key][0]; + } + } + } + $this->matrix = $matrix; + + return $this; + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/Operator.php b/lib/vendor/markbaker/matrix/classes/src/Operators/Operator.php new file mode 100644 index 0000000000..87d3f3b5d7 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/Operator.php @@ -0,0 +1,78 @@ +rows = $matrix->rows; + $this->columns = $matrix->columns; + $this->matrix = $matrix->toArray(); + } + + /** + * Compare the dimensions of the matrices being operated on to see if they are valid for addition/subtraction + * + * @param Matrix $matrix The second Matrix object on which the operation will be performed + * @throws Exception + */ + protected function validateMatchingDimensions(Matrix $matrix) + { + if (($this->rows != $matrix->rows) || ($this->columns != $matrix->columns)) { + throw new Exception('Matrices have mismatched dimensions'); + } + } + + /** + * Compare the dimensions of the matrices being operated on to see if they are valid for multiplication/division + * + * @param Matrix $matrix The second Matrix object on which the operation will be performed + * @throws Exception + */ + protected function validateReflectingDimensions(Matrix $matrix) + { + if ($this->columns != $matrix->rows) { + throw new Exception('Matrices have mismatched dimensions'); + } + } + + /** + * Return the result of the operation + * + * @return Matrix + */ + public function result() + { + return new Matrix($this->matrix); + } +} diff --git a/lib/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php b/lib/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php new file mode 100644 index 0000000000..57c0b147c1 --- /dev/null +++ b/lib/vendor/markbaker/matrix/classes/src/Operators/Subtraction.php @@ -0,0 +1,68 @@ +subtractMatrix($value); + } elseif (is_numeric($value)) { + return $this->subtractScalar($value); + } + + throw new Exception('Invalid argument for subtraction'); + } + + /** + * Execute the subtraction for a scalar + * + * @param mixed $value The numeric value to subtracted from the current base value + * @return $this The operation object, allowing multiple additions to be chained + **/ + protected function subtractScalar($value) + { + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + $this->matrix[$row][$column] -= $value; + } + } + + return $this; + } + + /** + * Execute the subtraction for a matrix + * + * @param Matrix $value The numeric value to subtract from the current base value + * @return $this The operation object, allowing multiple subtractions to be chained + * @throws Exception If the provided argument is not appropriate for the operation + **/ + protected function subtractMatrix(Matrix $value) + { + $this->validateMatchingDimensions($value); + + for ($row = 0; $row < $this->rows; ++$row) { + for ($column = 0; $column < $this->columns; ++$column) { + $this->matrix[$row][$column] -= $value->getValue($row + 1, $column + 1); + } + } + + return $this; + } +} diff --git a/lib/vendor/markbaker/matrix/composer.json b/lib/vendor/markbaker/matrix/composer.json new file mode 100644 index 0000000000..0e0337e34d --- /dev/null +++ b/lib/vendor/markbaker/matrix/composer.json @@ -0,0 +1,82 @@ +{ + "name": "markbaker/matrix", + "type": "library", + "description": "PHP Class for working with matrices", + "keywords": ["matrix", "vector", "mathematics"], + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "license": "MIT", + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "require": { + "php": "^5.6.0|^7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7|^6.0|7.0", + "phpmd/phpmd": "dev-master", + "sebastian/phpcpd": "^3.0", + "phploc/phploc": "^4", + "squizlabs/php_codesniffer": "^3.0@dev", + "phpcompatibility/php-compatibility": "dev-master", + "dealerdirect/phpcodesniffer-composer-installer": "dev-master" + }, + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + }, + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ] + }, + "autoload-dev": { + "psr-4": { + "MatrixTest\\": "unitTests/classes/src/" + }, + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ] + }, + "scripts": { + "style": "phpcs --standard=PSR2 --report-width=200 --report=summary,full classes/src/ unitTests/classes/src -n", + "test": "phpunit -c phpunit.xml.dist", + "mess": "phpmd classes/src/ xml codesize,unusedcode,design,naming -n", + "lines": "phploc classes/src/ -n", + "cpd": "phpcpd classes/src/ -n", + "versions": "phpcs --report-width=200 --report=summary,full classes/src/ --standard=PHPCompatibility --runtime-set testVersion 5.6- -n", + "coverage": "phpunit -c phpunit.xml.dist --coverage-text --coverage-html ./build/coverage" + }, + "minimum-stability": "dev" +} diff --git a/lib/vendor/markbaker/matrix/examples/test.php b/lib/vendor/markbaker/matrix/examples/test.php new file mode 100644 index 0000000000..b2bb027e9c --- /dev/null +++ b/lib/vendor/markbaker/matrix/examples/test.php @@ -0,0 +1,19 @@ +directsum(new Matrix\Matrix($grid2)); + +var_dump($new); diff --git a/lib/vendor/markbaker/matrix/infection.json.dist b/lib/vendor/markbaker/matrix/infection.json.dist new file mode 100644 index 0000000000..eddaa70a2e --- /dev/null +++ b/lib/vendor/markbaker/matrix/infection.json.dist @@ -0,0 +1,17 @@ +{ + "timeout": 1, + "source": { + "directories": [ + "classes\/src" + ] + }, + "logs": { + "text": "build/infection/text.log", + "summary": "build/infection/summary.log", + "debug": "build/infection/debug.log", + "perMutator": "build/infection/perMutator.md" + }, + "mutators": { + "@default": true + } +} diff --git a/lib/vendor/markbaker/matrix/license.md b/lib/vendor/markbaker/matrix/license.md new file mode 100644 index 0000000000..7329058f52 --- /dev/null +++ b/lib/vendor/markbaker/matrix/license.md @@ -0,0 +1,25 @@ +The MIT License (MIT) +===================== + +Copyright © `2018` `Mark Baker` + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/vendor/markbaker/matrix/phpstan.neon b/lib/vendor/markbaker/matrix/phpstan.neon new file mode 100644 index 0000000000..1607abd7c0 --- /dev/null +++ b/lib/vendor/markbaker/matrix/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + ignoreErrors: + - '#Property [A-Za-z\\]+::\$[A-Za-z]+ has no typehint specified#' + - '#Method [A-Za-z\\]+::[A-Za-z]+\(\) has no return typehint specified#' + checkMissingIterableValueType: false diff --git a/lib/vendor/masterexploder/phpthumb/.travis.yml b/lib/vendor/masterexploder/phpthumb/.travis.yml new file mode 100644 index 0000000000..625062e4ba --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/.travis.yml @@ -0,0 +1,4 @@ +language: php +php: + - 5.3 + - 5.4 diff --git a/lib/vendor/masterexploder/phpthumb/README.md b/lib/vendor/masterexploder/phpthumb/README.md new file mode 100644 index 0000000000..d1becab4c6 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/README.md @@ -0,0 +1,32 @@ +[![Build Status](https://secure.travis-ci.org/masterexploder/PHPThumb.png?branch=master)](http://travis-ci.org/masterexploder/PHPThumb) + +# PHP Thumb + +## NOTICE - +This project was recently updated to 2.0 and is PSR-0 compliant and supports Composer integration. Some parts of the documentation +are incorrect as they haven't been updated for the new version. Your 1.0 code is not compatible with 2.0! Please review the updated +examples for how to use the new version. + +PHP Thumb is a light-weight image manipulation library +aimed at thumbnail generation. It features the ability to +resize by width, height, and percentage, create custom crops, +or square crops from the center, and rotate the image. You can +also easily add custom functionality to the library through plugins. +It also features the ability to perform multiple manipulations per +instance (also known as chaining), without the need to save and +re-initialize the class with every manipulation. + +More information and documentation is available at the project's wiki: [https://github.com/masterexploder/PHPThumb/wiki](https://github.com/masterexploder/PHPThumb/wiki) + +## Documentation / Help + +I've tried to thoroughly document things as best I can, but here's a list of places to +find documentation / help: + +- [Documentation](http://wiki.github.com/iselby/PHPThumb/) - Your best friend, the library docs +- [Forums](http://phpthumb.gxdlabs.com/forums) - Got questions, comments, or feedback? This is the place to visit +- [Developer Docs](http://phpthumb.gxdlabs.com/apidocs) - Auto-generated docs for developers… these cover the code itself + +## License + +PHP Thumb is released under MIT license. diff --git a/lib/vendor/masterexploder/phpthumb/composer.json b/lib/vendor/masterexploder/phpthumb/composer.json new file mode 100644 index 0000000000..53b4279410 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/composer.json @@ -0,0 +1,28 @@ +{ + "name": "masterexploder/phpthumb", + "type": "library", + "license": "MIT", + "description": "A library for manipulating images in PHP.", + "keywords": ["image", "resize", "rotate"], + "require": { + "php": ">=5.3.0" + }, + "homepage": "https://github.com/masterexploder/PHPThumb", + "authors": [ + { + "name": "Ian Selby", + "email": "ian@gxdlabs.com" + }, + { + "name": "Jarrod Nettles", + "email": "jarrod.nettles@icloud.com" + } + ], + + "autoload": { + "psr-0": { + "PHPThumb": "src", + "PHPThumb\\Tests": "tests" + } + } +} diff --git a/lib/vendor/masterexploder/phpthumb/examples/README b/lib/vendor/masterexploder/phpthumb/examples/README new file mode 100644 index 0000000000..40eb80d262 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/README @@ -0,0 +1,10 @@ +README + +These files contain various examples for using the PHP +Thumb library. Feel free to do with them what you'd like. + +NOTE: The test images contained within are not my work. +DO NOT REDISTRIBUTE OR USE THESE IMAGES OUTSIDE THE SAMPLES. +If you are the owner of the images contained within, let me +know so I can properly credit you or remove the images at +your request. \ No newline at end of file diff --git a/lib/vendor/masterexploder/phpthumb/examples/crop_basic.php b/lib/vendor/masterexploder/phpthumb/examples/crop_basic.php new file mode 100644 index 0000000000..bc85c8aa9c --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/crop_basic.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->crop(100, 100, 300, 200); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/crop_basic_fromstring.php b/lib/vendor/masterexploder/phpthumb/examples/crop_basic_fromstring.php new file mode 100644 index 0000000000..ce563aa693 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/crop_basic_fromstring.php @@ -0,0 +1,41 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + + +$fileData = file_get_contents('test.jpg'); + +$thumb = new PHPThumb\GD($fileData); +$thumb->crop(100, 100, 300, 200); + +// $imageAsString will contain the image data suitable for saving in a database. +$imageAsString = $thumb->getImageAsString(); + +?> +

      Here's the Image Data:

      +Note: This should be a bunch of gibberish
      +
      + +

      Here's that data as an image:

      + diff --git a/lib/vendor/masterexploder/phpthumb/examples/crop_fromcenter.php b/lib/vendor/masterexploder/phpthumb/examples/crop_fromcenter.php new file mode 100644 index 0000000000..cf43946b0d --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/crop_fromcenter.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->cropFromCenter(200, 100); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/reflection.php b/lib/vendor/masterexploder/phpthumb/examples/reflection.php new file mode 100644 index 0000000000..ecd55c542d --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/reflection.php @@ -0,0 +1,33 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg', array(), array( + new PHPThumb\Plugins\Reflection(40, 40, 80, true, '#a4a4a4') +)); + +$thumb->adaptiveResize(250, 250); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/remote_image_resize.php b/lib/vendor/masterexploder/phpthumb/examples/remote_image_resize.php new file mode 100644 index 0000000000..f8eccdd855 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/remote_image_resize.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD('http://phpthumb.gxdlabs.com/wp-content/themes/phpthumb/images/header_bg.png'); +$thumb->resize(200, 200); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/resize_adaptive.php b/lib/vendor/masterexploder/phpthumb/examples/resize_adaptive.php new file mode 100644 index 0000000000..a4fa1582db --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/resize_adaptive.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->adaptiveResize(175, 175); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/resize_basic.php b/lib/vendor/masterexploder/phpthumb/examples/resize_basic.php new file mode 100644 index 0000000000..f5774c0264 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/resize_basic.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->resize(100, 100); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/resize_percentage.php b/lib/vendor/masterexploder/phpthumb/examples/resize_percentage.php new file mode 100644 index 0000000000..83b3663993 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/resize_percentage.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->resizePercent(50); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/rotate_advanced.php b/lib/vendor/masterexploder/phpthumb/examples/rotate_advanced.php new file mode 100644 index 0000000000..d248b8f9de --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/rotate_advanced.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->rotateImageNDegrees(180); +$thumb->show(); diff --git a/lib/vendor/masterexploder/phpthumb/examples/rotate_basic.php b/lib/vendor/masterexploder/phpthumb/examples/rotate_basic.php new file mode 100644 index 0000000000..c102ec53d1 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/rotate_basic.php @@ -0,0 +1,33 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->rotateImage('CW'); +$thumb->show(); + +// or: +// $thumb->rotate('CCW'); diff --git a/lib/vendor/masterexploder/phpthumb/examples/save_differentformat.php b/lib/vendor/masterexploder/phpthumb/examples/save_differentformat.php new file mode 100644 index 0000000000..6af64b022f --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/examples/save_differentformat.php @@ -0,0 +1,30 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @subpackage Examples + * @filesource + */ + +require_once '../vendor/autoload.php'; + +$thumb = new PHPThumb\GD(__DIR__ .'/../tests/resources/test.jpg'); +$thumb->adaptiveResize(300, 300); +$thumb->save('test.png', 'png'); diff --git a/lib/vendor/masterexploder/phpthumb/examples/test.jpg b/lib/vendor/masterexploder/phpthumb/examples/test.jpg new file mode 100644 index 0000000000..f6887d429f Binary files /dev/null and b/lib/vendor/masterexploder/phpthumb/examples/test.jpg differ diff --git a/lib/vendor/masterexploder/phpthumb/phpunit.xml.dist b/lib/vendor/masterexploder/phpthumb/phpunit.xml.dist new file mode 100644 index 0000000000..36839e717c --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + ./tests/PHPThumb/ + + + + + + ./src/ + + + diff --git a/lib/vendor/masterexploder/phpthumb/src/PHPThumb/GD.php b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/GD.php new file mode 100644 index 0000000000..350bf19134 --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/GD.php @@ -0,0 +1,1410 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ + +class GD extends PHPThumb +{ + /** + * The prior image (before manipulation) + * + * @var resource + */ + protected $oldImage; + + /** + * The working image (used during manipulation) + * + * @var resource + */ + protected $workingImage; + + /** + * The current dimensions of the image + * + * @var array + */ + protected $currentDimensions; + + /** + * The new, calculated dimensions of the image + * + * @var array + */ + protected $newDimensions; + + /** + * The options for this class + * + * This array contains various options that determine the behavior in + * various functions throughout the class. Functions note which specific + * option key / values are used in their documentation + * + * @var array + */ + protected $options; + + /** + * The maximum width an image can be after resizing (in pixels) + * + * @var int + */ + protected $maxWidth; + + /** + * The maximum height an image can be after resizing (in pixels) + * + * @var int + */ + protected $maxHeight; + + /** + * The percentage to resize the image by + * + * @var int + */ + protected $percent; + + /** + * @param string $fileName + * @param array $options + * @param array $plugins + */ + public function __construct($fileName, $options = array(), array $plugins = array()) + { + parent::__construct($fileName, $options, $plugins); + + $this->determineFormat(); + $this->verifyFormatCompatiblity(); + + switch ($this->format) { + case 'GIF': + $this->oldImage = imagecreatefromgif($this->fileName); + break; + case 'JPG': + $this->oldImage = imagecreatefromjpeg($this->fileName); + break; + case 'PNG': + $this->oldImage = imagecreatefrompng($this->fileName); + break; + case 'STRING': + $this->oldImage = imagecreatefromstring($this->fileName); + break; + } + + $this->currentDimensions = array ( + 'width' => imagesx($this->oldImage), + 'height' => imagesy($this->oldImage) + ); + } + + public function __destruct() + { + if (is_resource($this->oldImage)) { + imagedestroy($this->oldImage); + } + + if (is_resource($this->workingImage)) { + imagedestroy($this->workingImage); + } + } + + /** + * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color. + * @param $width + * @param $height + * @param array $color + * @return GD + */ + public function pad($width, $height, $color = array(255, 255, 255)) + { + // no resize - woohoo! + if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) { + return $this; + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($width, $height); + } else { + $this->workingImage = imagecreate($width, $height); + } + + // create the fill color + $fillColor = imagecolorallocate( + $this->workingImage, + $color[0], + $color[1], + $color[2] + ); + + // fill our working image with the fill color + imagefill( + $this->workingImage, + 0, + 0, + $fillColor + ); + + // copy the image into the center of our working image + imagecopyresampled( + $this->workingImage, + $this->oldImage, + intval(($width-$this->currentDimensions['width']) / 2), + intval(($height-$this->currentDimensions['height']) / 2), + 0, + 0, + $this->currentDimensions['width'], + $this->currentDimensions['height'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $width; + $this->currentDimensions['height'] = $height; + + return $this; + } + + /** + * Resizes an image to be no larger than $maxWidth or $maxHeight + * + * If either param is set to zero, then that dimension will not be considered as a part of the resize. + * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will + * also scale the image up to the maximum dimensions provided. + * + * @param int $maxWidth The maximum width of the image in pixels + * @param int $maxHeight The maximum height of the image in pixels + * @return \PHPThumb\GD + */ + public function resize($maxWidth = 0, $maxHeight = 0) + { + // make sure our arguments are valid + if (!is_numeric($maxWidth)) { + throw new \InvalidArgumentException('$maxWidth must be numeric'); + } + + if (!is_numeric($maxHeight)) { + throw new \InvalidArgumentException('$maxHeight must be numeric'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight; + $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth; + } else { + $this->maxHeight = intval($maxHeight); + $this->maxWidth = intval($maxWidth); + } + + // get the new dimensions... + $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']); + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } else { + $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } + + $this->preserveAlpha(); + + // and create the newly sized image + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + 0, + 0, + $this->newDimensions['newWidth'], + $this->newDimensions['newHeight'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->newDimensions['newWidth']; + $this->currentDimensions['height'] = $this->newDimensions['newHeight']; + + return $this; + } + + /** + * Adaptively Resizes the Image + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow (from the center) to get the image to be the size specified + * + * @param int $maxWidth + * @param int $maxHeight + * @return \PHPThumb\GD + */ + public function adaptiveResize($width, $height) + { + // make sure our arguments are valid + if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) { + throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero'); + } + + if (!is_numeric($width) || $width == 0) { + $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height']; + } + + if (!is_numeric($height) || $height == 0) { + $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width']; + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // now, figure out how to crop the rest of the image... + if ($this->currentDimensions['width'] > $this->maxWidth) { + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Adaptively Resizes the Image and Crops Using a Percentage + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow using a provided percentage to get the image to be the size specified. + * + * The percentage mean different things depending on the orientation of the original image. + * + * For Landscape images: + * --------------------- + * + * A percentage of 1 would crop the image all the way to the left, which would be the same as + * using adaptiveResizeQuadrant() with $quadrant = 'L' + * + * A percentage of 50 would crop the image to the center which would be the same as using + * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize() + * + * A percentage of 100 would crop the image to the image all the way to the right, etc, etc. + * Note that you can use any percentage between 1 and 100. + * + * For Portrait images: + * -------------------- + * + * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom + * + * @param int $maxWidth + * @param int $maxHeight + * @param int $percent + * @return \PHPThumb\GD + */ + public function adaptiveResizePercent($width, $height, $percent = 50) + { + // make sure our arguments are valid + if (!is_numeric($width) || $width == 0) { + throw new \InvalidArgumentException('$width must be numeric and greater than zero'); + } + + if (!is_numeric($height) || $height == 0) { + throw new \InvalidArgumentException('$height must be numeric and greater than zero'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // Crop the rest of the image using the quadrant + + if ($percent > 100) { + $percent = 100; + } elseif ($percent < 1) { + $percent = 1; + } + + if ($this->currentDimensions['width'] > $this->maxWidth) { + // Image is landscape + $maxCropX = $this->currentDimensions['width'] - $this->maxWidth; + $cropX = intval(($percent / 100) * $maxCropX); + + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + // Image is portrait + $maxCropY = $this->currentDimensions['height'] - $this->maxHeight; + $cropY = intval(($percent / 100) * $maxCropY); + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Adaptively Resizes the Image and Crops Using a Quadrant + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow using the quadrant to get the image to be the size specified. + * + * The quadrants available are Top, Bottom, Center, Left, and Right: + * + * + * +---+---+---+ + * | | T | | + * +---+---+---+ + * | L | C | R | + * +---+---+---+ + * | | B | | + * +---+---+---+ + * + * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't + * make sence since only the Left and Right would be available, then the Center quadrant will be used + * to crop. This would have exactly the same result as using adaptiveResize(). + * The same goes if your image is portrait and you choose either the Left or Right quadrants. + * + * @param int $maxWidth + * @param int $maxHeight + * @param string $quadrant T, B, C, L, R + * @return \PHPThumb\GD + */ + public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C') + { + // make sure our arguments are valid + if (!is_numeric($width) || $width == 0) { + throw new \InvalidArgumentException('$width must be numeric and greater than zero'); + } + + if (!is_numeric($height) || $height == 0) { + throw new \InvalidArgumentException('$height must be numeric and greater than zero'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // Crop the rest of the image using the quadrant + + if ($this->currentDimensions['width'] > $this->maxWidth) { + // Image is landscape + switch ($quadrant) { + case 'L': + $cropX = 0; + break; + case 'R': + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth)); + break; + case 'C': + default: + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); + break; + } + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + // Image is portrait + switch ($quadrant) { + case 'T': + $cropY = 0; + break; + case 'B': + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight)); + break; + case 'C': + default: + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); + break; + } + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Resizes an image by a given percent uniformly, + * Percentage should be whole number representation (i.e. 1-100) + * + * @param int $percent + * @return GD + * @throws \InvalidArgumentException + */ + public function resizePercent($percent = 0) + { + if (!is_numeric($percent)) { + throw new \InvalidArgumentException ('$percent must be numeric'); + } + + $this->percent = intval($percent); + + $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']); + + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } else { + $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } + + $this->preserveAlpha(); + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + 0, + 0, + $this->newDimensions['newWidth'], + $this->newDimensions['newHeight'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->newDimensions['newWidth']; + $this->currentDimensions['height'] = $this->newDimensions['newHeight']; + + return $this; + } + + /** + * Crops an image from the center with provided dimensions + * + * If no height is given, the width will be used as a height, thus creating a square crop + * + * @param int $cropWidth + * @param int $cropHeight + * @return \PHPThumb\GD + */ + public function cropFromCenter($cropWidth, $cropHeight = null) + { + if (!is_numeric($cropWidth)) { + throw new \InvalidArgumentException('$cropWidth must be numeric'); + } + + if ($cropHeight !== null && !is_numeric($cropHeight)) { + throw new \InvalidArgumentException('$cropHeight must be numeric'); + } + + if ($cropHeight === null) { + $cropHeight = $cropWidth; + } + + $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; + $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; + + $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2); + $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2); + + $this->crop($cropX, $cropY, $cropWidth, $cropHeight); + + return $this; + } + + /** + * Vanilla Cropping - Crops from x,y with specified width and height + * + * @param int $startX + * @param int $startY + * @param int $cropWidth + * @param int $cropHeight + * @return \PHPThumb\GD + */ + public function crop($startX, $startY, $cropWidth, $cropHeight) + { + // validate input + if (!is_numeric($startX)) { + throw new \InvalidArgumentException('$startX must be numeric'); + } + + if (!is_numeric($startY)) { + throw new \InvalidArgumentException('$startY must be numeric'); + } + + if (!is_numeric($cropWidth)) { + throw new \InvalidArgumentException('$cropWidth must be numeric'); + } + + if (!is_numeric($cropHeight)) { + throw new \InvalidArgumentException('$cropHeight must be numeric'); + } + + // do some calculations + $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; + $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; + + // ensure everything's in bounds + if (($startX + $cropWidth) > $this->currentDimensions['width']) { + $startX = ($this->currentDimensions['width'] - $cropWidth); + } + + if (($startY + $cropHeight) > $this->currentDimensions['height']) { + $startY = ($this->currentDimensions['height'] - $cropHeight); + } + + if ($startX < 0) { + $startX = 0; + } + + if ($startY < 0) { + $startY = 0; + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight); + } else { + $this->workingImage = imagecreate($cropWidth, $cropHeight); + } + + $this->preserveAlpha(); + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $startX, + $startY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $cropWidth; + $this->currentDimensions['height'] = $cropHeight; + + return $this; + } + + /** + * Rotates image either 90 degrees clockwise or counter-clockwise + * + * @param string $direction + * @retunrn \PHPThumb\GD + */ + public function rotateImage($direction = 'CW') + { + if ($direction == 'CW') { + $this->rotateImageNDegrees(90); + } else { + $this->rotateImageNDegrees(-90); + } + + return $this; + } + + /** + * Rotates image specified number of degrees + * + * @param int $degrees + * @return \PHPThumb\GD + */ + public function rotateImageNDegrees($degrees) + { + if (!is_numeric($degrees)) { + throw new \InvalidArgumentException('$degrees must be numeric'); + } + + if (!function_exists('imagerotate')) { + throw new \RuntimeException('Your version of GD does not support image rotation'); + } + + $this->workingImage = imagerotate($this->oldImage, $degrees, 0); + + $newWidth = $this->currentDimensions['height']; + $newHeight = $this->currentDimensions['width']; + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $newWidth; + $this->currentDimensions['height'] = $newHeight; + + return $this; + } + + /** + * Applies a filter to the image + * + * @param int $filter + * @return \PHPThumb\GD + */ + public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false) + { + if (!is_numeric($filter)) { + throw new \InvalidArgumentException('$filter must be numeric'); + } + + if (!function_exists('imagefilter')) { + throw new \RuntimeException('Your version of GD does not support image filters'); + } + + $result = false; + if ($arg1 === false) { + $result = imagefilter($this->oldImage, $filter); + } elseif ($arg2 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1); + } elseif ($arg3 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2); + } elseif ($arg4 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3); + } else { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4); + } + + if (!$result) { + throw new \RuntimeException('GD imagefilter failed'); + } + + $this->workingImage = $this->oldImage; + + return $this; + } + + /** + * Shows an image + * + * This function will show the current image by first sending the appropriate header + * for the format, and then outputting the image data. If headers have already been sent, + * a runtime exception will be thrown + * + * @param bool $rawData Whether or not the raw image stream should be output + * @return \PHPThumb\GD + */ + public function show($rawData = false) + { + //Execute any plugins + if ($this->plugins) { + foreach ($this->plugins as $plugin) { + /* @var $plugin \PHPThumb\PluginInterface */ + $plugin->execute($this); + } + } + + if (headers_sent() && php_sapi_name() != 'cli') { + throw new \RuntimeException('Cannot show image, headers have already been sent'); + } + + // When the interlace option equals true or false call imageinterlace else leave it to default + if ($this->options['interlace'] === true) { + imageinterlace($this->oldImage, 1); + } elseif ($this->options['interlace'] === false) { + imageinterlace($this->oldImage, 0); + } + + switch ($this->format) { + case 'GIF': + if ($rawData === false) { + header('Content-type: image/gif'); + } + imagegif($this->oldImage); + break; + case 'JPG': + if ($rawData === false) { + header('Content-type: image/jpeg'); + } + imagejpeg($this->oldImage, null, $this->options['jpegQuality']); + break; + case 'PNG': + case 'STRING': + if ($rawData === false) { + header('Content-type: image/png'); + } + imagepng($this->oldImage); + break; + } + + return $this; + } + + /** + * Returns the Working Image as a String + * + * This function is useful for getting the raw image data as a string for storage in + * a database, or other similar things. + * + * @return string + */ + public function getImageAsString() + { + $data = null; + ob_start(); + $this->show(true); + $data = ob_get_contents(); + ob_end_clean(); + + return $data; + } + + /** + * Saves an image + * + * This function will make sure the target directory is writeable, and then save the image. + * + * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this + * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a + * \RuntimeException is thrown. + * + * @param string $fileName The full path and filename of the image to save + * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG] + * @return \PHPThumb\GD + */ + public function save($fileName, $format = null) + { + $validFormats = array('GIF', 'JPG', 'PNG'); + $format = ($format !== null) ? strtoupper($format) : $this->format; + + if (!in_array($format, $validFormats)) { + throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}"); + } + + // make sure the directory is writeable + if (!is_writeable(dirname($fileName))) { + // try to correct the permissions + if ($this->options['correctPermissions'] === true) { + @chmod(dirname($fileName), 0777); + + // throw an exception if not writeable + if (!is_writeable(dirname($fileName))) { + throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}"); + } + } else { // throw an exception if not writeable + throw new \RuntimeException("File not writeable: {$fileName}"); + } + } + + // When the interlace option equals true or false call imageinterlace else leave it to default + if ($this->options['interlace'] === true) { + imageinterlace($this->oldImage, 1); + } elseif ($this->options['interlace'] === false) { + imageinterlace($this->oldImage, 0); + } + + switch ($format) { + case 'GIF': + imagegif($this->oldImage, $fileName); + break; + case 'JPG': + imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']); + break; + case 'PNG': + imagepng($this->oldImage, $fileName); + break; + } + + return $this; + } + + ################################# + # ----- GETTERS / SETTERS ----- # + ################################# + + /** + * Sets options for all operations. + * @param array $options + * @return GD + */ + public function setOptions(array $options = array()) + { + // we've yet to init the default options, so create them here + if (sizeof($this->options) == 0) { + $defaultOptions = array( + 'resizeUp' => false, + 'jpegQuality' => 100, + 'correctPermissions' => false, + 'preserveAlpha' => true, + 'alphaMaskColor' => array (255, 255, 255), + 'preserveTransparency' => true, + 'transparencyMaskColor' => array (0, 0, 0), + 'interlace' => null + ); + } else { // otherwise, let's use what we've got already + $defaultOptions = $this->options; + } + + $this->options = array_merge($defaultOptions, $options); + + return $this; + } + + /** + * Returns $currentDimensions. + * + * @see \PHPThumb\GD::$currentDimensions + */ + public function getCurrentDimensions() + { + return $this->currentDimensions; + } + + /** + * @param $currentDimensions + * @return GD + */ + public function setCurrentDimensions($currentDimensions) + { + $this->currentDimensions = $currentDimensions; + + return $this; + } + + /** + * @return int + */ + public function getMaxHeight() + { + return $this->maxHeight; + } + + /** + * @param $maxHeight + * @return GD + */ + public function setMaxHeight($maxHeight) + { + $this->maxHeight = $maxHeight; + + return $this; + } + + /** + * @return int + */ + public function getMaxWidth() + { + return $this->maxWidth; + } + + /** + * @param $maxWidth + * @return GD + */ + public function setMaxWidth($maxWidth) + { + $this->maxWidth = $maxWidth; + + return $this; + } + + /** + * Returns $newDimensions. + * + * @see \PHPThumb\GD::$newDimensions + */ + public function getNewDimensions() + { + return $this->newDimensions; + } + + /** + * Sets $newDimensions. + * + * @param object $newDimensions + * @see \PHPThumb\GD::$newDimensions + */ + public function setNewDimensions($newDimensions) + { + $this->newDimensions = $newDimensions; + + return $this; + } + + /** + * Returns $options. + * + * @see \PHPThumb\GD::$options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns $percent. + * + * @see \PHPThumb\GD::$percent + */ + public function getPercent() + { + return $this->percent; + } + + /** + * Sets $percent. + * + * @param object $percent + * @see \PHPThumb\GD::$percent + */ + public function setPercent($percent) + { + $this->percent = $percent; + + return $this; + } + + /** + * Returns $oldImage. + * + * @see \PHPThumb\GD::$oldImage + */ + public function getOldImage() + { + return $this->oldImage; + } + + /** + * Sets $oldImage. + * + * @param object $oldImage + * @see \PHPThumb\GD::$oldImage + */ + public function setOldImage($oldImage) + { + $this->oldImage = $oldImage; + + return $this; + } + + /** + * Returns $workingImage. + * + * @see \PHPThumb\GD::$workingImage + */ + public function getWorkingImage() + { + return $this->workingImage; + } + + /** + * Sets $workingImage. + * + * @param object $workingImage + * @see \PHPThumb\GD::$workingImage + */ + public function setWorkingImage($workingImage) + { + $this->workingImage = $workingImage; + + return $this; + } + + + ################################# + # ----- UTILITY FUNCTIONS ----- # + ################################# + + /** + * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcWidth($width, $height) + { + $newWidthPercentage = (100 * $this->maxWidth) / $width; + $newHeight = ($height * $newWidthPercentage) / 100; + + return array( + 'newWidth' => intval($this->maxWidth), + 'newHeight' => intval($newHeight) + ); + } + + /** + * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcHeight($width, $height) + { + $newHeightPercentage = (100 * $this->maxHeight) / $height; + $newWidth = ($width * $newHeightPercentage) / 100; + + return array( + 'newWidth' => ceil($newWidth), + 'newHeight' => ceil($this->maxHeight) + ); + } + + /** + * Calculates a new width and height for the image based on $this->percent and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcPercent($width, $height) + { + $newWidth = ($width * $this->percent) / 100; + $newHeight = ($height * $this->percent) / 100; + + return array( + 'newWidth' => ceil($newWidth), + 'newHeight' => ceil($newHeight) + ); + } + + /** + * Calculates the new image dimensions + * + * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight + * + * @param int $width + * @param int $height + */ + protected function calcImageSize($width, $height) + { + $newSize = array( + 'newWidth' => $width, + 'newHeight' => $height + ); + + if ($this->maxWidth > 0) { + $newSize = $this->calcWidth($width, $height); + + if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { + $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']); + } + } + + if ($this->maxHeight > 0) { + $newSize = $this->calcHeight($width, $height); + + if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { + $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']); + } + } + + $this->newDimensions = $newSize; + } + + /** + * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height + * + * @param int $width + * @param int $height + */ + protected function calcImageSizeStrict($width, $height) + { + // first, we need to determine what the longest resize dimension is.. + if ($this->maxWidth >= $this->maxHeight) { + // and determine the longest original dimension + if ($width > $height) { + $newDimensions = $this->calcHeight($width, $height); + + if ($newDimensions['newWidth'] < $this->maxWidth) { + $newDimensions = $this->calcWidth($width, $height); + } + } elseif ($height >= $width) { + $newDimensions = $this->calcWidth($width, $height); + + if ($newDimensions['newHeight'] < $this->maxHeight) { + $newDimensions = $this->calcHeight($width, $height); + } + } + } elseif ($this->maxHeight > $this->maxWidth) { + if ($width >= $height) { + $newDimensions = $this->calcWidth($width, $height); + + if ($newDimensions['newHeight'] < $this->maxHeight) { + $newDimensions = $this->calcHeight($width, $height); + } + } elseif ($height > $width) { + $newDimensions = $this->calcHeight($width, $height); + + if ($newDimensions['newWidth'] < $this->maxWidth) { + $newDimensions = $this->calcWidth($width, $height); + } + } + } + + $this->newDimensions = $newDimensions; + } + + /** + * Calculates new dimensions based on $this->percent and the provided dimensions + * + * @param int $width + * @param int $height + */ + protected function calcImageSizePercent($width, $height) + { + if ($this->percent > 0) { + $this->newDimensions = $this->calcPercent($width, $height); + } + } + + /** + * Determines the file format by mime-type + * + * This function will throw exceptions for invalid images / mime-types + * + */ + protected function determineFormat() + { + $formatInfo = getimagesize($this->fileName); + + // non-image files will return false + if ($formatInfo === false) { + if ($this->remoteImage) { + throw new \Exception("Could not determine format of remote image: {$this->fileName}"); + } else { + throw new \Exception("File is not a valid image: {$this->fileName}"); + } + } + + $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null; + + switch ($mimeType) { + case 'image/gif': + $this->format = 'GIF'; + break; + case 'image/jpeg': + $this->format = 'JPG'; + break; + case 'image/png': + $this->format = 'PNG'; + break; + default: + throw new \Exception("Image format not supported: {$mimeType}"); + } + } + + /** + * Makes sure the correct GD implementation exists for the file type + * + */ + protected function verifyFormatCompatiblity() + { + $isCompatible = true; + $gdInfo = gd_info(); + + switch ($this->format) { + case 'GIF': + $isCompatible = $gdInfo['GIF Create Support']; + break; + case 'JPG': + $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false; + break; + case 'PNG': + $isCompatible = $gdInfo[$this->format . ' Support']; + break; + default: + $isCompatible = false; + } + + if (!$isCompatible) { + // one last check for "JPEG" instead + $isCompatible = $gdInfo['JPEG Support']; + + if (!$isCompatible) { + throw new \Exception("Your GD installation does not support {$this->format} image types"); + } + } + } + + /** + * Preserves the alpha or transparency for PNG and GIF files + * + * Alpha / transparency will not be preserved if the appropriate options are set to false. + * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a + * champ... that's the nature of GIFs tho, so no huge surprise. + * + * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :) + * + */ + protected function preserveAlpha() + { + if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) { + imagealphablending($this->workingImage, false); + + $colorTransparent = imagecolorallocatealpha( + $this->workingImage, + $this->options['alphaMaskColor'][0], + $this->options['alphaMaskColor'][1], + $this->options['alphaMaskColor'][2], + 0 + ); + + imagefill($this->workingImage, 0, 0, $colorTransparent); + imagesavealpha($this->workingImage, true); + } + // preserve transparency in GIFs... this is usually pretty rough tho + if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) { + $colorTransparent = imagecolorallocate( + $this->workingImage, + $this->options['transparencyMaskColor'][0], + $this->options['transparencyMaskColor'][1], + $this->options['transparencyMaskColor'][2] + ); + + imagecolortransparent($this->workingImage, $colorTransparent); + imagetruecolortopalette($this->workingImage, true, 256); + } + } +} diff --git a/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PHPThumb.php b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PHPThumb.php new file mode 100644 index 0000000000..bfb7ee10fc --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PHPThumb.php @@ -0,0 +1,143 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ + +abstract class PHPThumb +{ + /** + * The name of the file we're manipulating + * This must include the path to the file (absolute paths recommended) + * + * @var string + */ + protected $fileName; + + /** + * What the file format is (mime-type) + * + * @var string + */ + protected $format; + + /** + * Whether or not the image is hosted remotely + * + * @var bool + */ + protected $remoteImage; + + /** + * An array of attached plugins to execute in order. + * @var array + */ + protected $plugins; + + /** + * @param $fileName + * @param array $options + * @param array $plugins + */ + public function __construct($fileName, array $options = array(), array $plugins = array()) + { + $this->fileName = $fileName; + $this->remoteImage = false; + + if(!$this->validateRequestedResource($fileName)) { + throw new \InvalidArgumentException("Image file not found: {$fileName}"); + } + + $this->setOptions($options); + + $this->plugins = $plugins; + } + + abstract public function setOptions(array $options = array()); + + /** + * Check the provided filename/url. If it is a url, validate that it is properly + * formatted. If it is a file, check to make sure that it actually exists on + * the filesystem. + * + * @param $filename + * @return bool + */ + protected function validateRequestedResource($filename) + { + if(false !== filter_var($filename, FILTER_VALIDATE_URL)) { + $this->remoteImage = true; + return true; + } + + if(file_exists($filename)) { + return true; + } + + return false; + } + + /** + * Returns the filename. + * @return string + */ + public function getFileName() + { + return $this->fileName; + } + + /** + * Sets the filename. + * @param $fileName + * @return PHPThumb + */ + public function setFileName($fileName) + { + $this->fileName = $fileName; + + return $this; + } + + /** + * Returns the format. + * @return string + */ + public function getFormat() + { + return $this->format; + } + + /** + * Sets the format. + * @param $format + * @return PHPThumb + */ + public function setFormat($format) + { + $this->format = $format; + + return $this; + } + + /** + * Returns whether the image exists remotely, i.e. it was loaded via a URL. + * @return bool + */ + public function getIsRemoteImage() + { + return $this->remoteImage; + } +} diff --git a/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PluginInterface.php b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PluginInterface.php new file mode 100644 index 0000000000..56df9768ab --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/src/PHPThumb/PluginInterface.php @@ -0,0 +1,12 @@ + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @version 3.0 + * @package PhpThumb + * @filesource + */ + +/** + * GD Reflection Lib Plugin + * + * This plugin allows you to create those fun Apple(tm)-style reflections in your images + * + * @package PhpThumb + * @subpackage Plugins + */ +class Reflection implements \PHPThumb\PluginInterface +{ + protected $currentDimensions; + protected $workingImage; + protected $newImage; + protected $options; + + protected $percent; + protected $reflection; + protected $white; + protected $border; + protected $borderColor; + + public function __construct($percent, $reflection, $white, $border, $borderColor) + { + $this->percent = $percent; + $this->reflection = $reflection; + $this->white = $white; + $this->border = $border; + $this->borderColor = $borderColor; + } + + /** + * @param \PHPThumb\PHPThumb $phpthumb + * @return \PHPThumb\PHPThumb + */ + public function execute($phpthumb) + { + $this->currentDimensions = $phpthumb->getCurrentDimensions(); + $this->workingImage = $phpthumb->getWorkingImage(); + $this->newImage = $phpthumb->getOldImage(); + $this->options = $phpthumb->getOptions(); + + $width = $this->currentDimensions['width']; + $height = $this->currentDimensions['height']; + $this->reflectionHeight = intval($height * ($this->reflection / 100)); + $newHeight = $height + $this->reflectionHeight; + $reflectedPart = $height * ($this->percent / 100); + + $this->workingImage = imagecreatetruecolor($width, $newHeight); + + imagealphablending($this->workingImage, true); + + $colorToPaint = imagecolorallocatealpha( + $this->workingImage, + 255, + 255, + 255, + 0 + ); + + imagefilledrectangle( + $this->workingImage, + 0, + 0, + $width, + $newHeight, + $colorToPaint + ); + + imagecopyresampled( + $this->workingImage, + $this->newImage, + 0, + 0, + 0, + $reflectedPart, + $width, + $this->reflectionHeight, + $width, + ($height - $reflectedPart) + ); + + $this->imageFlipVertical(); + + imagecopy( + $this->workingImage, + $this->newImage, + 0, + 0, + 0, + 0, + $width, + $height + ); + + imagealphablending($this->workingImage, true); + + for ($i = 0; $i < $this->reflectionHeight; $i++) { + $colorToPaint = imagecolorallocatealpha( + $this->workingImage, + 255, + 255, + 255, + ($i / $this->reflectionHeight * -1 + 1) * $this->white + ); + + imagefilledrectangle( + $this->workingImage, + 0, + $height + $i, + $width, + $height + $i, + $colorToPaint + ); + } + + if ($this->border == true) { + $rgb = $this->hex2rgb($this->borderColor, false); + $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]); + + //top line + imageline( + $this->workingImage, + 0, + 0, + $width, + 0, + $colorToPaint + ); + + //bottom line + imageline( + $this->workingImage, + 0, + $height, + $width, + $height, + $colorToPaint + ); + + //left line + imageline( + $this->workingImage, + 0, + 0, + 0, + $height, + $colorToPaint + ); + + //right line + imageline( + $this->workingImage, + $width - 1, + 0, + $width - 1, + $height, + $colorToPaint + ); + } + + if ($phpthumb->getFormat() == 'PNG') { + $colorTransparent = imagecolorallocatealpha( + $this->workingImage, + $this->options['alphaMaskColor'][0], + $this->options['alphaMaskColor'][1], + $this->options['alphaMaskColor'][2], + 0 + ); + + imagefill($this->workingImage, 0, 0, $colorTransparent); + imagesavealpha($this->workingImage, true); + } + + $phpthumb->setOldImage($this->workingImage); + $this->currentDimensions['width'] = $width; + $this->currentDimensions['height'] = $newHeight; + $phpthumb->setCurrentDimensions($this->currentDimensions); + + return $phpthumb; + } + + /** + * Flips the image vertically + * + */ + protected function imageFlipVertical () + { + $x_i = imagesx($this->workingImage); + $y_i = imagesy($this->workingImage); + + for ($x = 0; $x < $x_i; $x++) { + for ($y = 0; $y < $y_i; $y++) { + imagecopy( + $this->workingImage, + $this->workingImage, + $x, + $y_i - $y - 1, + $x, + $y, + 1, + 1 + ); + } + } + } + + /** + * Converts a hex color to rgb tuples + * + * @return mixed + * @param string $hex + * @param bool $asString + */ + protected function hex2rgb ($hex, $asString = false) + { + // strip off any leading # + if (0 === strpos($hex, '#')) { + $hex = substr($hex, 1); + } elseif (0 === strpos($hex, '&H')) { + $hex = substr($hex, 2); + } + + // break into hex 3-tuple + $cutpoint = ceil(strlen($hex) / 2)-1; + $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3); + + // convert each tuple to decimal + $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0); + $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0); + $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0); + + return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb); + } +} diff --git a/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/GDTest.php b/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/GDTest.php new file mode 100644 index 0000000000..1b33440bba --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/GDTest.php @@ -0,0 +1,37 @@ +gif = new GD(__DIR__ . '/../resources/test.gif'); + $this->jpg = new GD(__DIR__ . '/../resources/test.jpg'); + $this->png = new GD(__DIR__ . '/../resources/test.png'); + } + + public function testLoadFileTypes() + { + self::assertSame('GIF', $this->gif->getFormat()); + self::assertSame('JPG', $this->jpg->getFormat()); + self::assertSame('PNG', $this->png->getFormat()); + } + + /** + * This test might seem pointless but it runs the __destruct and gets us to + * 100% code coverage. + */ + public function testImageDestroy() + { + $testImage = new GD(__DIR__ . '/../resources/test.gif'); + unset($testImage); + self::assertSame(false, isset($testImage)); + } +} diff --git a/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/LoadTest.php b/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/LoadTest.php new file mode 100644 index 0000000000..8f3d3be99f --- /dev/null +++ b/lib/vendor/masterexploder/phpthumb/tests/PHPThumb/LoadTest.php @@ -0,0 +1,64 @@ +thumb = new GD(__DIR__ . '/../resources/test.jpg'); + } + + public function testLoadFile() + { + self::assertSame(array('width' => 500, 'height' => 375), $this->thumb->getCurrentDimensions()); + self::assertSame(array( + 'resizeUp' => false, + 'jpegQuality' => 100, + 'correctPermissions' => false, + 'preserveAlpha' => true, + 'alphaMaskColor' => array ( + 0 => 255, + 1 => 255, + 2 => 255), + 'preserveTransparency' => true, + 'transparencyMaskColor' => array ( + 0 => 0, + 1 => 0, + 2 => 0), + 'interlace' => null), $this->thumb->getOptions()); + + self::assertSame('JPG', $this->thumb->getFormat()); + self::assertSame(__DIR__ . '/../resources/test.jpg', $this->thumb->getFileName()); + } + + public function testSetFormat() + { + $this->thumb->setFormat('PNG'); + self::assertSame('PNG', $this->thumb->getFormat()); + } + + public function testSetFileName() + { + $this->thumb->setFilename('mytest.jpg'); + self::assertSame('mytest.jpg', $this->thumb->getFilename()); + } + + public function testLoadExternalImage() + { + /* $gravatarThumb = new GD('https://en.gravatar.com/userimage/1132703/2ccbcfbea4a1b3b8d955c1e7746b882b.jpg'); + self::assertSame(true, $gravatarThumb->getIsRemoteImage()); */ + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testNonexistentFile() + { + $madeupThumb = new GD('nosuchimage.jpg'); + } +} diff --git a/lib/vendor/masterexploder/phpthumb/tests/resources/test.gif b/lib/vendor/masterexploder/phpthumb/tests/resources/test.gif new file mode 100644 index 0000000000..f67f9953b3 Binary files /dev/null and b/lib/vendor/masterexploder/phpthumb/tests/resources/test.gif differ diff --git a/lib/vendor/masterexploder/phpthumb/tests/resources/test.jpg b/lib/vendor/masterexploder/phpthumb/tests/resources/test.jpg new file mode 100644 index 0000000000..f6887d429f Binary files /dev/null and b/lib/vendor/masterexploder/phpthumb/tests/resources/test.jpg differ diff --git a/lib/vendor/masterexploder/phpthumb/tests/resources/test.png b/lib/vendor/masterexploder/phpthumb/tests/resources/test.png new file mode 100644 index 0000000000..5b1ce30ff1 Binary files /dev/null and b/lib/vendor/masterexploder/phpthumb/tests/resources/test.png differ diff --git a/lib/vendor/mobiledetect/mobiledetectlib/LICENSE b/lib/vendor/mobiledetect/mobiledetectlib/LICENSE new file mode 100644 index 0000000000..69d9874c90 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Şerban Ghiţă, Nick Ilyin and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json b/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json new file mode 100644 index 0000000000..8cd27038ca --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json @@ -0,0 +1 @@ +{"version":"2.8.45","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+|\\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\\b-[0-9]+","Pixel":"; \\bPixel\\b","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6","Dell":"Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b|XT1068|XT1092|XT1052","Samsung":"\\bSamsung\\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N|SM-G781B|SM-A805N|SM-G965F","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332","Asus":"Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD|ASUS_X00TD","Xiaomi":"^(?!.*\\bx11\\b).*xiaomi.*$|POCOPHONE F1|\\bMI\\b 8|\\bMi\\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro|N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C|M2007J1SC","NokiaLumia":"Lumia [0-9]{3,4}","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","Wiko":"KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo (3DS|Switch)","Amoi":"Amoi","INQ":"INQ","OnePlus":"ONEPLUS","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)","GoogleTablet":"Android.*Pixel C","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536|SM-T837A|SM-X200|SM-T220|SM-T870|SM-X906C|SM-X700|SM-X706|SM-X706B|SM-X706U|SM-X706N|SM-X800|SM-X806|SM-X806B|SM-X806U|SM-X806N|SM-X900|SM-X906|SM-X906B|SM-X906U|SM-X906N|SM-P613","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\\bP027\\b|\\bP024\\b|\\bP00C\\b","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30|A3-A40","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002","LenovoTablet":"Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L|TB-J606F|TB-X606F|TB-X306X|YT-J706X","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","XiaomiTablet":"21051182G","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","NokiaLumiaTablet":"Lumia 2520","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"Android.*(bq)?.*\\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\\b|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09|BG2-U01|BG2-W09|BG2-U03","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z930|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android [0-9.]+; [a-z-]+; \\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9|TECNO DP8D","JXDTablet":"Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","VerizonTablet":"QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","OndaTablet":"\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+|V10 \\b4G\\b","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b","AocTablet":"MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712","MpmanTablet":"MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","WolderTablet":"miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b","MediacomTablet":"M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","LeaderTablet":"TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","KocasoTablet":"\\b(TB-1207)\\b","HisenseTablet":"\\b(F5281|E2371)\\b","Hudl":"Hudl HT7S3|Hudl 2","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b|\\bQTAQZ3\\b|WVT101|TM1088|KT107"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS.*Mobile|Android.*Chrome\/[.0-9]* Mobile","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+$|Coast\/[0-9.]+","Skyfire":"Skyfire","Edge":"EdgiOS.*Mobile|Mobile Safari\/[.0-9]* Edge","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version((?!\\bEdgiOS\\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari","WeChat":"\\bMicroMessenger\\b","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger","PaleMoon":"Android.*PaleMoon|Mobile.*PaleMoon"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad|AppleCoreMedia","iPadOS":"CPU OS 13","SailfishOS":"Sailfish","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"Bot":"Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot|Semrush|DotBot|PetalBot|MetadataScraper","MobileBot":"Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2","DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}} \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php b/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php new file mode 100644 index 0000000000..55a8823719 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php @@ -0,0 +1,1692 @@ + (since 2012) + * @author Nick Ilyin + * @author: Victor Stanciu (original author) + * + * @version 2.8.45 + * + * Auto-generated isXXXX() magic methods. + * php -a examples/dump_magic_methods.php + * + * @method bool isiPhone() + * @method bool isBlackBerry() + * @method bool isPixel() + * @method bool isHTC() + * @method bool isNexus() + * @method bool isDell() + * @method bool isMotorola() + * @method bool isSamsung() + * @method bool isLG() + * @method bool isSony() + * @method bool isAsus() + * @method bool isXiaomi() + * @method bool isNokiaLumia() + * @method bool isMicromax() + * @method bool isPalm() + * @method bool isVertu() + * @method bool isPantech() + * @method bool isFly() + * @method bool isWiko() + * @method bool isiMobile() + * @method bool isSimValley() + * @method bool isWolfgang() + * @method bool isAlcatel() + * @method bool isNintendo() + * @method bool isAmoi() + * @method bool isINQ() + * @method bool isOnePlus() + * @method bool isGenericPhone() + * @method bool isiPad() + * @method bool isNexusTablet() + * @method bool isGoogleTablet() + * @method bool isSamsungTablet() + * @method bool isKindle() + * @method bool isSurfaceTablet() + * @method bool isHPTablet() + * @method bool isAsusTablet() + * @method bool isBlackBerryTablet() + * @method bool isHTCtablet() + * @method bool isMotorolaTablet() + * @method bool isNookTablet() + * @method bool isAcerTablet() + * @method bool isToshibaTablet() + * @method bool isLGTablet() + * @method bool isFujitsuTablet() + * @method bool isPrestigioTablet() + * @method bool isLenovoTablet() + * @method bool isDellTablet() + * @method bool isYarvikTablet() + * @method bool isMedionTablet() + * @method bool isArnovaTablet() + * @method bool isIntensoTablet() + * @method bool isIRUTablet() + * @method bool isMegafonTablet() + * @method bool isEbodaTablet() + * @method bool isAllViewTablet() + * @method bool isArchosTablet() + * @method bool isAinolTablet() + * @method bool isNokiaLumiaTablet() + * @method bool isSonyTablet() + * @method bool isPhilipsTablet() + * @method bool isCubeTablet() + * @method bool isCobyTablet() + * @method bool isMIDTablet() + * @method bool isMSITablet() + * @method bool isSMiTTablet() + * @method bool isRockChipTablet() + * @method bool isFlyTablet() + * @method bool isbqTablet() + * @method bool isHuaweiTablet() + * @method bool isNecTablet() + * @method bool isPantechTablet() + * @method bool isBronchoTablet() + * @method bool isVersusTablet() + * @method bool isZyncTablet() + * @method bool isPositivoTablet() + * @method bool isNabiTablet() + * @method bool isKoboTablet() + * @method bool isDanewTablet() + * @method bool isTexetTablet() + * @method bool isPlaystationTablet() + * @method bool isTrekstorTablet() + * @method bool isPyleAudioTablet() + * @method bool isAdvanTablet() + * @method bool isDanyTechTablet() + * @method bool isGalapadTablet() + * @method bool isMicromaxTablet() + * @method bool isKarbonnTablet() + * @method bool isAllFineTablet() + * @method bool isPROSCANTablet() + * @method bool isYONESTablet() + * @method bool isChangJiaTablet() + * @method bool isGUTablet() + * @method bool isPointOfViewTablet() + * @method bool isOvermaxTablet() + * @method bool isHCLTablet() + * @method bool isDPSTablet() + * @method bool isVistureTablet() + * @method bool isCrestaTablet() + * @method bool isMediatekTablet() + * @method bool isConcordeTablet() + * @method bool isGoCleverTablet() + * @method bool isModecomTablet() + * @method bool isVoninoTablet() + * @method bool isECSTablet() + * @method bool isStorexTablet() + * @method bool isVodafoneTablet() + * @method bool isEssentielBTablet() + * @method bool isRossMoorTablet() + * @method bool isiMobileTablet() + * @method bool isTolinoTablet() + * @method bool isAudioSonicTablet() + * @method bool isAMPETablet() + * @method bool isSkkTablet() + * @method bool isTecnoTablet() + * @method bool isJXDTablet() + * @method bool isiJoyTablet() + * @method bool isFX2Tablet() + * @method bool isXoroTablet() + * @method bool isViewsonicTablet() + * @method bool isVerizonTablet() + * @method bool isOdysTablet() + * @method bool isCaptivaTablet() + * @method bool isIconbitTablet() + * @method bool isTeclastTablet() + * @method bool isOndaTablet() + * @method bool isJaytechTablet() + * @method bool isBlaupunktTablet() + * @method bool isDigmaTablet() + * @method bool isEvolioTablet() + * @method bool isLavaTablet() + * @method bool isAocTablet() + * @method bool isMpmanTablet() + * @method bool isCelkonTablet() + * @method bool isWolderTablet() + * @method bool isMediacomTablet() + * @method bool isMiTablet() + * @method bool isNibiruTablet() + * @method bool isNexoTablet() + * @method bool isLeaderTablet() + * @method bool isUbislateTablet() + * @method bool isPocketBookTablet() + * @method bool isKocasoTablet() + * @method bool isHisenseTablet() + * @method bool isHudl() + * @method bool isTelstraTablet() + * @method bool isGenericTablet() + * @method bool isAndroidOS() + * @method bool isBlackBerryOS() + * @method bool isPalmOS() + * @method bool isSymbianOS() + * @method bool isWindowsMobileOS() + * @method bool isWindowsPhoneOS() + * @method bool isiOS() + * @method bool isiPadOS() + * @method bool isSailfishOS() + * @method bool isMeeGoOS() + * @method bool isMaemoOS() + * @method bool isJavaOS() + * @method bool iswebOS() + * @method bool isbadaOS() + * @method bool isBREWOS() + * @method bool isChrome() + * @method bool isDolfin() + * @method bool isOpera() + * @method bool isSkyfire() + * @method bool isEdge() + * @method bool isIE() + * @method bool isFirefox() + * @method bool isBolt() + * @method bool isTeaShark() + * @method bool isBlazer() + * @method bool isSafari() + * @method bool isWeChat() + * @method bool isUCBrowser() + * @method bool isbaiduboxapp() + * @method bool isbaidubrowser() + * @method bool isDiigoBrowser() + * @method bool isMercury() + * @method bool isObigoBrowser() + * @method bool isNetFront() + * @method bool isGenericBrowser() + * @method bool isPaleMoon() + * @method bool isBot() + * @method bool isMobileBot() + * @method bool isDesktopMode() + * @method bool isTV() + * @method bool isWebKit() + * @method bool isConsole() + * @method bool isWatch() + + */ +class Mobile_Detect +{ + /** + * Mobile detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_MOBILE = 'mobile'; + + /** + * Extended detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_EXTENDED = 'extended'; + + /** + * A frequently used regular expression to extract version #s. + * + * @deprecated since version 2.6.9 + */ + const VER = '([\w._\+]+)'; + + /** + * Top-level device. + */ + const MOBILE_GRADE_A = 'A'; + + /** + * Mid-level device. + */ + const MOBILE_GRADE_B = 'B'; + + /** + * Low-level device. + */ + const MOBILE_GRADE_C = 'C'; + + /** + * Stores the version number of the current release. + */ + const VERSION = '2.8.45'; + + /** + * A type for the version() method indicating a string return value. + */ + const VERSION_TYPE_STRING = 'text'; + + /** + * A type for the version() method indicating a float return value. + */ + const VERSION_TYPE_FLOAT = 'float'; + + /** + * A cache for resolved matches + * @var array + */ + protected $cache = array(); + + /** + * The User-Agent HTTP header is stored in here. + * @var string + */ + protected $userAgent = null; + + /** + * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. + * @var array + */ + protected $httpHeaders = array(); + + /** + * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer. + * @var array + */ + protected $cloudfrontHeaders = array(); + + /** + * The matching Regex. + * This is good for debug. + * @var string + */ + protected $matchingRegex = null; + + /** + * The matches extracted from the regex expression. + * This is good for debug. + * + * @var string + */ + protected $matchesArray = null; + + /** + * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED. + * + * @deprecated since version 2.6.9 + * + * @var string + */ + protected $detectionType = self::DETECTION_TYPE_MOBILE; + + /** + * HTTP headers that trigger the 'isMobile' detection + * to be true. + * + * @var array + */ + protected static $mobileHeaders = array( + + 'HTTP_ACCEPT' => array('matches' => array( + // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ + 'application/x-obml2d', + // BlackBerry devices. + 'application/vnd.rim.html', + 'text/vnd.wap.wml', + 'application/vnd.wap.xhtml+xml' + )), + 'HTTP_X_WAP_PROFILE' => null, + 'HTTP_X_WAP_CLIENTID' => null, + 'HTTP_WAP_CONNECTION' => null, + 'HTTP_PROFILE' => null, + // Reported by Opera on Nokia devices (eg. C3). + 'HTTP_X_OPERAMINI_PHONE_UA' => null, + 'HTTP_X_NOKIA_GATEWAY_ID' => null, + 'HTTP_X_ORANGE_ID' => null, + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, + 'HTTP_X_HUAWEI_USERID' => null, + // Reported by Windows Smartphones. + 'HTTP_UA_OS' => null, + // Reported by Verizon, Vodafone proxy system. + 'HTTP_X_MOBILE_GATEWAY' => null, + // Seen this on HTC Sensation. SensationXE_Beats_Z715e. + 'HTTP_X_ATT_DEVICEID' => null, + // Seen this on a HTC. + 'HTTP_UA_CPU' => array('matches' => array('ARM')), + ); + + /** + * List of mobile devices (phones). + * + * @var array + */ + protected static $phoneDevices = array( + 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes + 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+|\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\b-[0-9]+', + 'Pixel' => '; \bPixel\b', + 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel', + 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6', + // @todo: Is 'Dell Streak' a tablet or a phone? ;) + 'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', + 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b|XT1068|XT1092|XT1052', + 'Samsung' => '\bSamsung\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N|SM-G781B|SM-A805N|SM-G965F', + 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710', + 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332', + 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD|ASUS_X00TD', + 'Xiaomi' => '^(?!.*\bx11\b).*xiaomi.*$|POCOPHONE F1|\bMI\b 8|\bMi\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro|N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C|M2007J1SC', + 'NokiaLumia' => 'Lumia [0-9]{3,4}', + // http://www.micromaxinfo.com/mobiles/smartphones + // Added because the codes might conflict with Acer Tablets. + 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', + // @todo Complete the regex. + 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; + 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;) + // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) + // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. + 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', + // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. + 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', + // http://fr.wikomobile.com + 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM', + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // Added simvalley mobile just for fun. They have some interesting devices. + // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html + 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', + // Wolfgang - a brand that is sold by Aldi supermarkets. + // http://www.wolfgangmobile.com/ + 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q', + 'Alcatel' => 'Alcatel', + 'Nintendo' => 'Nintendo (3DS|Switch)', + // http://en.wikipedia.org/wiki/Amoi + 'Amoi' => 'Amoi', + // http://en.wikipedia.org/wiki/INQ + 'INQ' => 'INQ', + 'OnePlus' => 'ONEPLUS', + // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 + 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser', + ); + + /** + * List of tablet devices. + * + * @var array + */ + protected static $tabletDevices = array( + // @todo: check for mobile friendly emails topic. + 'iPad' => 'iPad|iPad.*Mobile', + // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$ + // @see #442 + // @todo Merge NexusTablet into GoogleTablet. + 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)', + // https://en.wikipedia.org/wiki/Pixel_C + 'GoogleTablet' => 'Android.*Pixel C', + 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536|SM-T837A|SM-X200|SM-T220|SM-T870|SM-X906C|SM-X700|SM-X706|SM-X706B|SM-X706U|SM-X706N|SM-X800|SM-X806|SM-X806B|SM-X806U|SM-X806N|SM-X900|SM-X906|SM-X906B|SM-X906U|SM-X906N|SM-P613', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone. + // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)', + // Only the Surface tablets with Windows RT are considered mobile. + // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx + 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', + // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT + 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', + // Watch out for PadFone, see #132. + // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ + 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b', + 'BlackBerryTablet' => 'PlayBook|RIM Tablet', + 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', + 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', + 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', + // http://www.acer.ro/ac/ro/RO/content/drivers + // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) + // http://us.acer.com/ac/en/US/content/group/tablets + // http://www.acer.de/ac/de/DE/content/models/tablets/ + // Can conflict with Micromax and Motorola phones codes. + 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30|A3-A40', + // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ + // http://us.toshiba.com/tablets/tablet-finder + // http://www.toshiba.co.jp/regza/tablet/ + 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', + // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html + // http://www.lg.com/us/tablets + 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', + 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', + // Prestigio Tablets http://www.prestigio.com/support + 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002', + // http://support.lenovo.com/en_GB/downloads/default.page?# + 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L|TB-J606F|TB-X606F|TB-X306X|YT-J706X', + // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets + 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', + 'XiaomiTablet' => '21051182G', + // http://www.yarvik.com/en/matrix/tablets/ + 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', + 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', + 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', + // http://www.intenso.de/kategorie_en.php?kategorie=33 + // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate + 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', + // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ + 'IRUTablet' => 'M702pro', + 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', + // http://www.e-boda.ro/tablete-pc.html + 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', + // http://www.allview.ro/produse/droseries/lista-tablete-pc/ + 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', + // http://wiki.archosfans.com/index.php?title=Main_Page + // @note Rewrite the regex format after we add more UAs. + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', + // http://www.ainol.com/plugin.php?identifier=ainol&module=product + 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + 'NokiaLumiaTablet' => 'Lumia 2520', + // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER + // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser + // http://www.sony.jp/support/tablet/ + 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712', + // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 + 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', + // db + http://www.cube-tablet.com/buy-products.html + 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', + // http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', + // http://www.match.net.cn/products.asp + 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10', + // http://www.msi.com/support + // @todo Research the Windows Tablets. + 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', + // @todo http://www.kyoceramobile.com/support/drivers/ + // 'KyoceraTablet' => null, + // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/ + // 'IntextTablet' => null, + // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) + // http://www.imp3.net/14/show.php?itemid=20454 + 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', + // http://www.rock-chips.com/index.php?do=prod&pid=2 + 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', + // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ + 'FlyTablet' => 'IQ310|Fly Vision', + // http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bqTablet' => 'Android.*(bq)?.*\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\b|Maxwell.*Lite|Maxwell.*Plus', + // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 + // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) + 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09|BG2-U01|BG2-W09|BG2-U03', + // Nec or Medias Tab + 'NecTablet' => '\bN-06D|\bN-08D', + // Pantech Tablets: http://www.pantechusa.com/phones/ + 'PantechTablet' => 'Pantech.*P4100', + // Broncho Tablets: http://www.broncho.cn/ (hard to find) + 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', + // http://versusuk.com/support.html + 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', + // http://www.zync.in/index.php/our-products/tablet-phablets + 'ZyncTablet' => 'z1000|Z99 2G|z930|z990|z909|Z919|z900', // Removed "z999" because of https://github.com/serbanghita/Mobile-Detect/issues/717 + // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', + // https://www.nabitablet.com/ + 'NabiTablet' => 'Android.*\bNabi', + 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', + // French Danew Tablets http://www.danew.com/produits-tablette.php + 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', + // Texet Tablets and Readers http://www.texet.ru/tablet/ + 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', + // Avoid detecting 'PLAYSTATION 3' as mobile. + 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', + // http://www.trekstor.de/surftabs.html + 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab', + // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets + 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', + // http://www.advandigital.com/index.php?link=content-product&jns=JP001 + // because of the short codenames we have to include whitespaces to reduce the possible conflicts. + 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', + // http://www.danytech.com/category/tablet-pc + 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', + // http://www.galapad.net/product.html ; https://github.com/serbanghita/Mobile-Detect/issues/761 + 'GalapadTablet' => 'Android [0-9.]+; [a-z-]+; \bG1\b', + // http://www.micromaxinfo.com/tablet/funbook + 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', + // http://www.karbonnmobiles.com/products_tablet.php + 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', + // http://www.myallfine.com/Products.asp + 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', + // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', + // http://www.yonesnav.com/products/products.php + 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', + // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) + 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', + // http://www.gloryunion.cn/products.asp + // http://www.allwinnertech.com/en/apply/mobile.html + // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) + // @todo: Softwiner tablets? + // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. + 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G + // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 + 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', + // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ + // @todo: add more tests. + 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027', + // http://hclmetablet.com/India/index.php + 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', + // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html + 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', + // http://www.visture.com/index.asp + 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', + // http://www.mijncresta.nl/tablet + 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', + // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 + 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', + // Concorde tab + 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', + // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ + 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', + // Modecom Tablets - http://www.modecom.eu/tablets/portal/ + 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', + // Vonino Tablets + 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', + // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 + 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', + // Storex Tablets - http://storex.fr/espace_client/support.html + // @note: no need to add all the tablet codes since they are guided by the first regex. + 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', + // Generic Vodafone tablets. + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400', + // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb + // Aka: http://www.essentielb.fr/ + 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', + // Ross & Moor - http://ross-moor.ru/ + 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', + // i-mobile http://product.i-mobilephone.com/Mobile_Device + 'iMobileTablet' => 'i-mobile i-note', + // http://www.tolino.de/de/vergleichen/ + 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', + // AudioSonic - a Kmart brand + // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 + 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', + // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ + // @todo: add them gradually to avoid conflicts. + 'AMPETablet' => 'Android.* A78 ', + // Skk Mobile - http://skkmobile.com.ph/product_tablets.php + 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', + // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 + 'TecnoTablet' => 'TECNO P9|TECNO DP8D', + // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 + 'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ + 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', + // http://www.intracon.eu/tablet + 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', + // http://www.xoro.de/produkte/ + // @note: Might be the same brand with 'Simply tablets' + 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', + // http://www1.viewsonic.com/products/computing/tablets/ + 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', + // https://www.verizonwireless.com/tablets/verizon/ + 'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1', + // http://www.odys.de/web/internet-tablet_en.html + 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10', + // http://www.captiva-power.de/products.html#tablets-en + 'CaptivaTablet' => 'CAPTIVA PAD', + // IconBIT - http://www.iconbit.com/products/tablets/ + 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', + // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 + 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi', + // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price + 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b', + 'JaytechTablet' => 'TPC-PA762', + 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', + // http://www.digma.ru/support/download/ + // @todo: Ebooks also (if requested) + 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b', + // http://www.evolioshop.com/ro/tablete-pc.html + // http://www.evolio.ro/support/downloads_static.html?cat=2 + // @todo: Research some more + 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', + // @todo http://www.lavamobiles.com/tablets-data-cards + 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b', + // http://www.breezetablet.com/ + 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712', + // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/ + 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010', + // https://www.celkonmobiles.com/?_a=categoryphones&sid=2 + 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b', + // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab + 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b', + 'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA', + // http://www.mi.com/en + 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b', + // http://www.nbru.cn/index.html + 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One', + // http://navroad.com/products/produkty/tablety/ + // http://navroad.com/products/produkty/tablety/ + 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', + // http://leader-online.com/new_site/product-category/tablets/ + // http://www.leader-online.net.au/List/Tablet + 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100', + // http://www.datawind.com/ubislate/ + 'UbislateTablet' => 'UbiSlate[\s]?7C', + // http://www.pocketbook-int.com/ru/support + 'PocketBookTablet' => 'Pocketbook', + // http://www.kocaso.com/product_tablet.html + 'KocasoTablet' => '\b(TB-1207)\b', + // http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm + 'HisenseTablet' => '\b(F5281|E2371)\b', + // http://www.tesco.com/direct/hudl/ + 'Hudl' => 'Hudl HT7S3|Hudl 2', + // http://www.telstra.com.au/home-phone/thub-2/ + 'TelstraTablet' => 'T-Hub2', + 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107' + ); + + /** + * List of mobile Operating Systems. + * + * @var array + */ + protected static $operatingSystems = array( + 'AndroidOS' => 'Android', + 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', + 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', + 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', + // @reference: http://en.wikipedia.org/wiki/Windows_Mobile + 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;', + // @reference: http://en.wikipedia.org/wiki/Windows_Phone + // http://wifeng.cn/?r=blog&a=view&id=106 + // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx + // http://msdn.microsoft.com/library/ms537503.aspx + // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx + 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', + 'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia', + // https://en.wikipedia.org/wiki/IPadOS + 'iPadOS' => 'CPU OS 13', + // @reference https://en.m.wikipedia.org/wiki/Sailfish_OS + // https://sailfishos.org/ + 'SailfishOS' => 'Sailfish', + // http://en.wikipedia.org/wiki/MeeGo + // @todo: research MeeGo in UAs + 'MeeGoOS' => 'MeeGo', + // http://en.wikipedia.org/wiki/Maemo + // @todo: research Maemo in UAs + 'MaemoOS' => 'Maemo', + 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 + 'webOS' => 'webOS|hpwOS', + 'badaOS' => '\bBada\b', + 'BREWOS' => 'BREW', + ); + + /** + * List of mobile User Agents. + * + * IMPORTANT: This is a list of only mobile browsers. + * Mobile Detect 2.x supports only mobile browsers, + * it was never designed to detect all browsers. + * The change will come in 2017 in the 3.x release for PHP7. + * + * @var array + */ + protected static $browsers = array( + //'Vivaldi' => 'Vivaldi', + // @reference: https://developers.google.com/chrome/mobile/docs/user-agent + 'Chrome' => '\bCrMo\b|CriOS.*Mobile|Android.*Chrome/[.0-9]* Mobile', + 'Dolfin' => '\bDolfin\b', + 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+', + 'Skyfire' => 'Skyfire', + // Added "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 + 'Edge' => 'EdgiOS.*Mobile|Mobile Safari/[.0-9]* Edge', + 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile', + 'Bolt' => 'bolt', + 'TeaShark' => 'teashark', + 'Blazer' => 'Blazer', + // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 + // Excluded "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 + 'Safari' => 'Version((?!\bEdgiOS\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari', + // http://en.wikipedia.org/wiki/Midori_(web_browser) + //'Midori' => 'midori', + //'Tizen' => 'Tizen', + 'WeChat' => '\bMicroMessenger\b', + 'UCBrowser' => 'UC.*Browser|UCWEB', + 'baiduboxapp' => 'baiduboxapp', + 'baidubrowser' => 'baidubrowser', + // https://github.com/serbanghita/Mobile-Detect/issues/7 + 'DiigoBrowser' => 'DiigoBrowser', + // http://www.puffinbrowser.com/index.php + // https://github.com/serbanghita/Mobile-Detect/issues/752 + // 'Puffin' => 'Puffin', + // http://mercury-browser.com/index.html + 'Mercury' => '\bMercury\b', + // http://en.wikipedia.org/wiki/Obigo_Browser + 'ObigoBrowser' => 'Obigo', + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NF-Browser', + // @reference: http://en.wikipedia.org/wiki/Minimo + // http://en.wikipedia.org/wiki/Vision_Mobile_Browser + 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', + // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser) + 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon', + ); + + /** + * Utilities. + * + * @var array + */ + protected static $utilities = array( + // Experimental. When a mobile device wants to switch to 'Desktop Mode'. + // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ + // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 + // https://developers.facebook.com/docs/sharing/webmasters/crawler/ + 'Bot' => 'Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot|Semrush|DotBot|PetalBot|MetadataScraper', + 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2', + 'DesktopMode' => 'WPDesktop', + 'TV' => 'SonyDTV|HbbTV', // experimental + 'WebKit' => '(webkit)[ /]([\w.]+)', + // @todo: Include JXD consoles. + 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b', + 'Watch' => 'SM-V700', + ); + + /** + * All possible HTTP headers that represent the + * User-Agent string. + * + * @var array + */ + protected static $uaHttpHeaders = array( + // The default User-Agent string. + 'HTTP_USER_AGENT', + // Header can occur on devices using Opera Mini. + 'HTTP_X_OPERAMINI_PHONE_UA', + // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ + 'HTTP_X_DEVICE_USER_AGENT', + 'HTTP_X_ORIGINAL_USER_AGENT', + 'HTTP_X_SKYFIRE_PHONE', + 'HTTP_X_BOLT_PHONE_UA', + 'HTTP_DEVICE_STOCK_UA', + 'HTTP_X_UCBROWSER_DEVICE_UA' + ); + + /** + * The individual segments that could exist in a User-Agent string. VER refers to the regular + * expression defined in the constant self::VER. + * + * @var array + */ + protected static $properties = array( + + // Build + 'Mobile' => 'Mobile/[VER]', + 'Build' => 'Build/[VER]', + 'Version' => 'Version/[VER]', + 'VendorID' => 'VendorID/[VER]', + + // Devices + 'iPad' => 'iPad.*CPU[a-z ]+[VER]', + 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', + 'iPod' => 'iPod.*CPU[a-z ]+[VER]', + //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), + 'Kindle' => 'Kindle/[VER]', + + // Browser + 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), + 'Coast' => array('Coast/[VER]'), + 'Dolfin' => 'Dolfin/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox + 'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'), + 'Fennec' => 'Fennec/[VER]', + // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx + 'Edge' => 'Edge/[VER]', + 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'), + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NetFront/[VER]', + 'NokiaBrowser' => 'NokiaBrowser/[VER]', + 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), + 'Opera Mini' => 'Opera Mini/[VER]', + 'Opera Mobi' => 'Version/[VER]', + 'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ), + 'MQQBrowser' => 'MQQBrowser/[VER]', + 'MicroMessenger' => 'MicroMessenger/[VER]', + 'baiduboxapp' => 'baiduboxapp/[VER]', + 'baidubrowser' => 'baidubrowser/[VER]', + 'SamsungBrowser' => 'SamsungBrowser/[VER]', + 'Iron' => 'Iron/[VER]', + // @note: Safari 7534.48.3 is actually Version 5.1. + // @note: On BlackBerry the Version is overwriten by the OS. + 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), + 'Skyfire' => 'Skyfire/[VER]', + 'Tizen' => 'Tizen/[VER]', + 'Webkit' => 'webkit[ /][VER]', + 'PaleMoon' => 'PaleMoon/[VER]', + 'SailfishBrowser' => 'SailfishBrowser/[VER]', + + // Engine + 'Gecko' => 'Gecko/[VER]', + 'Trident' => 'Trident/[VER]', + 'Presto' => 'Presto/[VER]', + 'Goanna' => 'Goanna/[VER]', + + // OS + 'iOS' => ' \bi?OS\b [VER][ ;]{1}', + 'Android' => 'Android [VER]', + 'Sailfish' => 'Sailfish [VER]', + 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), + 'BREW' => 'BREW [VER]', + 'Java' => 'Java/[VER]', + // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx + // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases + 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), + 'Windows Phone' => 'Windows Phone [VER]', + 'Windows CE' => 'Windows CE/[VER]', + // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd + 'Windows NT' => 'Windows NT [VER]', + 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), + 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), + ); + + /** + * Construct an instance of this class. + * + * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. + * If left empty, will use the global _SERVER['HTTP_*'] vars instead. + * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT + * from the $headers array instead. + */ + public function __construct( + array $headers = null, + $userAgent = null + ) { + $this->setHttpHeaders($headers); + $this->setUserAgent($userAgent); + } + + /** + * Get the current script version. + * This is useful for the demo.php file, + * so people can check on what version they are testing + * for mobile devices. + * + * @return string The version number in semantic version format. + */ + public static function getScriptVersion() + { + return self::VERSION; + } + + /** + * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. + * + * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract + * the headers. The default null is left for backwards compatibility. + */ + public function setHttpHeaders($httpHeaders = null) + { + // use global _SERVER if $httpHeaders aren't defined + if (!is_array($httpHeaders) || !count($httpHeaders)) { + $httpHeaders = $_SERVER; + } + + // clear existing headers + $this->httpHeaders = array(); + + // Only save HTTP headers. In PHP land, that means only _SERVER vars that + // start with HTTP_. + foreach ($httpHeaders as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $this->httpHeaders[$key] = $value; + } + } + + // In case we're dealing with CloudFront, we need to know. + $this->setCfHeaders($httpHeaders); + } + + /** + * Retrieves the HTTP headers. + * + * @return array + */ + public function getHttpHeaders() + { + return $this->httpHeaders; + } + + /** + * Retrieves a particular header. If it doesn't exist, no exception/error is caused. + * Simply null is returned. + * + * @param string $header The name of the header to retrieve. Can be HTTP compliant such as + * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the + * all-caps, HTTP_ prefixed, underscore separated awesomeness. + * + * @return string|null The value of the header. + */ + public function getHttpHeader($header) + { + // are we using PHP-flavored headers? + if (strpos($header, '_') === false) { + $header = str_replace('-', '_', $header); + $header = strtoupper($header); + } + + // test the alternate, too + $altHeader = 'HTTP_' . $header; + + //Test both the regular and the HTTP_ prefix + if (isset($this->httpHeaders[$header])) { + return $this->httpHeaders[$header]; + } elseif (isset($this->httpHeaders[$altHeader])) { + return $this->httpHeaders[$altHeader]; + } + + return null; + } + + public function getMobileHeaders() + { + return self::$mobileHeaders; + } + + /** + * Get all possible HTTP headers that + * can contain the User-Agent string. + * + * @return array List of HTTP headers. + */ + public function getUaHttpHeaders() + { + return self::$uaHttpHeaders; + } + + + /** + * Set CloudFront headers + * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device + * + * @param array $cfHeaders List of HTTP headers + * + * @return boolean If there were CloudFront headers to be set + */ + public function setCfHeaders($cfHeaders = null) { + // use global _SERVER if $cfHeaders aren't defined + if (!is_array($cfHeaders) || !count($cfHeaders)) { + $cfHeaders = $_SERVER; + } + + // clear existing headers + $this->cloudfrontHeaders = array(); + + // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that + // start with cloudfront-. + $response = false; + foreach ($cfHeaders as $key => $value) { + if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') { + $this->cloudfrontHeaders[strtoupper($key)] = $value; + $response = true; + } + } + + return $response; + } + + /** + * Retrieves the cloudfront headers. + * + * @return array + */ + public function getCfHeaders() + { + return $this->cloudfrontHeaders; + } + + /** + * @param string $userAgent + * @return string + */ + private function prepareUserAgent($userAgent) { + $userAgent = trim($userAgent); + $userAgent = substr($userAgent, 0, 500); + return $userAgent; + } + + /** + * Set the User-Agent to be used. + * + * @param string $userAgent The user agent string to set. + * + * @return string|null + */ + public function setUserAgent($userAgent = null) + { + // Invalidate cache due to #375 + $this->cache = array(); + + if (false === empty($userAgent)) { + return $this->userAgent = $this->prepareUserAgent($userAgent); + } else { + $this->userAgent = null; + foreach ($this->getUaHttpHeaders() as $altHeader) { + if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) + $this->userAgent .= $this->httpHeaders[$altHeader] . " "; + } + } + + if (!empty($this->userAgent)) { + return $this->userAgent = $this->prepareUserAgent($this->userAgent); + } + } + + if (count($this->getCfHeaders()) > 0) { + return $this->userAgent = 'Amazon CloudFront'; + } + return $this->userAgent = null; + } + + /** + * Retrieve the User-Agent. + * + * @return string|null The user agent if it's set. + */ + public function getUserAgent() + { + return $this->userAgent; + } + + /** + * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or + * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. + * + * @deprecated since version 2.6.9 + * + * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default + * parameter is null which will default to self::DETECTION_TYPE_MOBILE. + */ + public function setDetectionType($type = null) + { + if ($type === null) { + $type = self::DETECTION_TYPE_MOBILE; + } + + if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) { + return; + } + + $this->detectionType = $type; + } + + public function getMatchingRegex() + { + return $this->matchingRegex; + } + + public function getMatchesArray() + { + return $this->matchesArray; + } + + /** + * Retrieve the list of known phone devices. + * + * @return array List of phone devices. + */ + public static function getPhoneDevices() + { + return self::$phoneDevices; + } + + /** + * Retrieve the list of known tablet devices. + * + * @return array List of tablet devices. + */ + public static function getTabletDevices() + { + return self::$tabletDevices; + } + + /** + * Alias for getBrowsers() method. + * + * @return array List of user agents. + */ + public static function getUserAgents() + { + return self::getBrowsers(); + } + + /** + * Retrieve the list of known browsers. Specifically, the user agents. + * + * @return array List of browsers / user agents. + */ + public static function getBrowsers() + { + return self::$browsers; + } + + /** + * Retrieve the list of known utilities. + * + * @return array List of utilities. + */ + public static function getUtilities() + { + return self::$utilities; + } + + /** + * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*(). + * + * @deprecated since version 2.6.9 + * + * @return array All the rules (but not extended). + */ + public static function getMobileDetectionRules() + { + static $rules; + + if (!$rules) { + $rules = array_merge( + self::getPhoneDevices(), + self::getTabletDevices(), + self::getOperatingSystems(), + self::getBrowsers() + ); + } + + return $rules; + + } + + /** + * Method gets the mobile detection rules + utilities. + * The reason this is separate is because utilities rules + * don't necessary imply mobile. This method is used inside + * the new $detect->is('stuff') method. + * + * @deprecated since version 2.6.9 + * + * @return array All the rules + extended. + */ + public function getMobileDetectionRulesExtended() + { + static $rules; + + if (!$rules) { + // Merge all rules together. + $rules = array_merge( + static::getPhoneDevices(), + static::getTabletDevices(), + static::getOperatingSystems(), + static::getBrowsers(), + static::getUtilities() + ); + } + + return $rules; + } + + /** + * Retrieve the current set of rules. + * + * @deprecated since version 2.6.9 + * + * @return array + */ + public function getRules() + { + if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { + return self::getMobileDetectionRulesExtended(); + } else { + return self::getMobileDetectionRules(); + } + } + + /** + * Retrieve the list of mobile operating systems. + * + * @return array The list of mobile operating systems. + */ + public static function getOperatingSystems() + { + return self::$operatingSystems; + } + + /** + * Check the HTTP headers for signs of mobile. + * This is the fastest mobile check possible; it's used + * inside isMobile() method. + * + * @return bool + */ + public function checkHttpHeadersForMobile() + { + + foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { + if (isset($this->httpHeaders[$mobileHeader])) { + if (isset($matchType['matches']) && is_array($matchType['matches'])) { + foreach ($matchType['matches'] as $_match) { + if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) { + return true; + } + } + + return false; + } else { + return true; + } + } + } + + return false; + + } + + /** + * Magic overloading method. + * + * @method boolean is[...]() + * @param string $name + * @param array $arguments + * @return mixed + * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' + */ + public function __call($name, $arguments) + { + // make sure the name starts with 'is', otherwise + if (substr($name, 0, 2) !== 'is') { + throw new BadMethodCallException("No such method exists: $name"); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + $key = substr($name, 2); + + return $this->matchUAAgainstKey($key); + } + + /** + * Find a detection rule that matches the current User-agent. + * + * @param null $userAgent deprecated + * @return boolean + */ + protected function matchDetectionRulesAgainstUA($userAgent = null) + { + // Begin general search. + foreach ($this->getRules() as $_regex) { + if (empty($_regex)) { + continue; + } + + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * Search for a certain key in the rules array. + * If the key is found then try to match the corresponding + * regex against the User-Agent. + * + * @param string $key + * + * @return boolean + */ + protected function matchUAAgainstKey($key) + { + // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. + $key = strtolower($key); + if (false === isset($this->cache[$key])) { + + // change the keys to lower case + $_rules = array_change_key_case($this->getRules()); + + if (false === empty($_rules[$key])) { + $this->cache[$key] = $this->match($_rules[$key]); + } + + if (false === isset($this->cache[$key])) { + $this->cache[$key] = false; + } + } + + return $this->cache[$key]; + } + + /** + * Check if the device is mobile. + * Returns true if any type of mobile device detected, including special ones + * @param null $userAgent deprecated + * @param null $httpHeaders deprecated + * @return bool + */ + public function isMobile($userAgent = null, $httpHeaders = null) + { + + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') { + return true; + } + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + if ($this->checkHttpHeadersForMobile()) { + return true; + } else { + return $this->matchDetectionRulesAgainstUA(); + } + + } + + /** + * Check if the device is a tablet. + * Return true if any type of tablet device is detected. + * + * @param string $userAgent deprecated + * @param array $httpHeaders deprecated + * @return bool + */ + public function isTablet($userAgent = null, $httpHeaders = null) + { + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') { + return true; + } + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + foreach (static::getTabletDevices() as $_regex) { + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * This method checks for a certain property in the + * userAgent. + * @todo: The httpHeaders part is not yet used. + * + * @param string $key + * @param string $userAgent deprecated + * @param string $httpHeaders deprecated + * @return bool|int|null + */ + public function is($key, $userAgent = null, $httpHeaders = null) + { + // Set the UA and HTTP headers only if needed (eg. batch mode). + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); + + return $this->matchUAAgainstKey($key); + } + + /** + * Some detection rules are relative (not standard), + * because of the diversity of devices, vendors and + * their conventions in representing the User-Agent or + * the HTTP headers. + * + * This method will be used to check custom regexes against + * the User-Agent string. + * + * @param $regex + * @param string $userAgent + * @return bool + * + * @todo: search in the HTTP headers too. + */ + public function match($regex, $userAgent = null) + { + if (!\is_string($userAgent) && !\is_string($this->userAgent)) { + return false; + } + + $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : (is_string($this->userAgent) ? $this->userAgent : '')), $matches); + // If positive match is found, store the results for debug. + if ($match) { + $this->matchingRegex = $regex; + $this->matchesArray = $matches; + } + + return $match; + } + + /** + * Get the properties array. + * + * @return array + */ + public static function getProperties() + { + return self::$properties; + } + + /** + * Prepare the version number. + * + * @todo Remove the error supression from str_replace() call. + * + * @param string $ver The string version, like "2.6.21.2152"; + * + * @return float + */ + public function prepareVersionNo($ver) + { + $ver = str_replace(array('_', ' ', '/'), '.', $ver); + $arrVer = explode('.', $ver, 2); + + if (isset($arrVer[1])) { + $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. + } + + return (float) implode('.', $arrVer); + } + + /** + * Check the version of the given property in the User-Agent. + * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) + * + * @param string $propertyName The name of the property. See self::getProperties() array + * keys for all possible properties. + * @param string $type Either self::VERSION_TYPE_STRING to get a string value or + * self::VERSION_TYPE_FLOAT indicating a float value. This parameter + * is optional and defaults to self::VERSION_TYPE_STRING. Passing an + * invalid parameter will default to the this type as well. + * + * @return string|float|false The version of the property we are trying to extract. + */ + public function version($propertyName, $type = self::VERSION_TYPE_STRING) + { + if (empty($propertyName)) { + return false; + } + + if (!\is_string($this->userAgent)) { + return false; + } + + // set the $type to the default if we don't recognize the type + if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { + $type = self::VERSION_TYPE_STRING; + } + + $properties = static::getProperties(); + + // Check if the property exists in the properties array. + if (true === isset($properties[$propertyName])) { + + // Prepare the pattern to be matched. + // Make sure we always deal with an array (string is converted). + $properties[$propertyName] = (array) $properties[$propertyName]; + + foreach ($properties[$propertyName] as $propertyMatchString) { + + $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); + + // Identify and extract the version. + preg_match(sprintf('#%s#is', $propertyPattern), (is_string($this->userAgent) ? $this->userAgent : ''), $match); + + if (false === empty($match[1])) { + $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); + + return $version; + } + + } + + } + + return false; + } + + /** + * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. + * @deprecated This is no longer being maintained, it was an experiment at the time. + * @return string One of the self::MOBILE_GRADE_* constants. + */ + public function mobileGrade() + { + $isMobile = $this->isMobile(); + + if ( + // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0) + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 || + + // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) + // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM + // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices + // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 + ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || + + // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8) + $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 || + + // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10) + $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 || + // Blackberry Playbook (1.0-2.0) - Tested on PlayBook + $this->match('Playbook.*Tablet') || + + // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0) + ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) || + // Palm WebOS 3.0 - Tested on HP TouchPad + $this->match('hp.*TouchPad') || + + // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices + ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) || + + // Chrome for Android - Tested on Android 4.0, 4.1 device + ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) || + + // Skyfire 4.1 - Tested on Android 2.3 device + ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || + + // Opera Mobile 11.5-12: Tested on Android 2.3 + ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) || + + // Meego 1.2 - Tested on Nokia 950 and N9 + $this->is('MeeGoOS') || + + // Sailfish OS + $this->is('SailfishOS') || + + // Tizen (pre-release) - Tested on early hardware + $this->is('Tizen') || + + // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser + // @todo: more tests here! + $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 || + + // UC Browser - Tested on Android 2.3 device + ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || + + // Kindle 3 and Fire - Tested on the built-in WebKit browser for each + ( $this->match('Kindle Fire') || + $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) || + + // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet + $this->is('AndroidOS') && $this->is('NookTablet') || + + // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7 + $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile || + + // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7 + $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile || + + // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7 + $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile || + + // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 + $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile || + + // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 + $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile + ){ + return self::MOBILE_GRADE_A; + } + + if ( + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || + + // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 + $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || + + //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 + ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 && + ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) || + + // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) + $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || + + // @todo: report this (tested on Nokia N71) + $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS') + ){ + return self::MOBILE_GRADE_B; + } + + if ( + // Blackberry 4.x - Tested on the Curve 8330 + $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 || + // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) + $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 || + + // Tested on original iPhone (3.1), iPhone 3 (3.2) + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 || + + // Internet Explorer 7 and older - Tested on Windows XP + $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile + ){ + return self::MOBILE_GRADE_C; + } + + // All older smartphone platforms and featurephones - Any device that doesn't support media queries + // will receive the basic, C grade experience. + return self::MOBILE_GRADE_C; + } +} diff --git a/lib/vendor/mobiledetect/mobiledetectlib/README.md b/lib/vendor/mobiledetect/mobiledetectlib/README.md new file mode 100644 index 0000000000..2e99f35808 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/README.md @@ -0,0 +1,348 @@ +![Mobile Detect](http://demo.mobiledetect.net/logo-github.png) + +> Motto: "Every business should have a detection script to detect mobile readers." + +![Workflow status](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/2.8.x-test.yml?style=flat-square) +![Latest tag](https://img.shields.io/github/v/tag/serbanghita/Mobile-Detect?filter=2.8.*&style=flat-square) +![Monthly Downloads](https://img.shields.io/packagist/dm/mobiledetect/mobiledetectlib?style=flat-square&label=installs) +![Total Downloads](https://img.shields.io/packagist/dt/mobiledetect/mobiledetectlib?style=flat-square&label=installs) +![MIT License](https://img.shields.io/packagist/l/mobiledetect/mobiledetectlib?style=flat-square) + +#### About + +Mobile Detect is a lightweight PHP class for detecting mobile devices (including tablets). +It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment. + +*Why* + +Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_, +_fast_ and _relevant_ to your users. Mobile Detect class is a +[server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy, +it is not a replacement for CSS3 media queries or other forms of client-side feature detection. + +*How* + +We're committed to make Mobile_Detect the best open-source mobile detection resource and this is why before +each release we're running [unit tests](./tests) and research and update the detection rules on **monthly** basis. + +*Who* + +See [the history](./docs/HISTORY.md) of the project. + +#### Version guidance + +| Version | Tests | Namespace | Code | PHP Version | Status | +|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------------------------------------------------------------|-------------|----------------------| +| 2.8.x | [![5x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/2.8.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `\Mobile_Detect` | [2.8](https://github.com/serbanghita/Mobile-Detect/tree/2.8.x) | \>=5.6,<7.0 | Deprecated | +| 3.74.x | [![7x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/3.74.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `Detection\MobileDetect` | [3.74](https://github.com/serbanghita/Mobile-Detect/tree/3.74.x) | \>=7.4,<8.0 | LTS | +| 4.8.x | [![7x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/4.8.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `Detection\MobileDetect` | [4.8](https://github.com/serbanghita/Mobile-Detect/tree/4.8.x) | \>=8.0 | Current, **Recommended** | + + +**JetBrains** is sponsoring the project by providing licenses for [PHPStorm](https://www.jetbrains.com/phpstorm/) and +[DataGrip](https://www.jetbrains.com/datagrip/). + +#### Install + +**Download and include manually** +> Use this to quickly test the demo. + +* [Download the latest release](../../tags) +* [Mobile_Detect.php](./Mobile_Detect.php) + +```php +require_once "libs/Mobile_Detect.php"; +``` + +**Install as a [composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)** +> Use this method to get continuous updates. + +``` +composer require mobiledetect/mobiledetectlib +``` +or include the dependency in the `composer.json` file: +```json +{ + "require": { + "mobiledetect/mobiledetectlib": "^2.8" + } +} +``` + +#### Demo + +* [:iphone: Live demo!](https://demo.mobiledetect.net) +* [Code examples](../../wiki/Code-examples) + +#### Contribute + +*Submit a PR* +> Submit a pull request but before make sure you read [how to contribute](docs/CONTRIBUTING.md) guide. + +*Donate* + +|Paypal| +|------| +|[Donate :+1:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)| + + +I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases. +I would highly appreciate any money donations that will keep the research going. + +Special thanks to the community :+1: for donations, JetBrains team for the continuous support and [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo. + +#### Modules, plugins, ports +> [Submit new module, plugin, port](../../issues/new?title=New%203rd%20party%20module&body=Name,%20Link%20and%20Description%20of%20the%20module.) + +:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates. +:point_right: When including the class into your `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts. + +**JavaScript** + +* mobile-detect.js - A [JavaScript port](https://github.com/hgoebl/mobile-detect.js) of Mobile-Detect class. Made by [Heinrich Goebl](https://github.com/hgoebl). + +**Varnish Cache** + +* [Varnish Mobile Detect](https://github.com/willemk/varnish-mobiletranslate) - Drop-in varnish solution to mobile user +detection based on the Mobile-Detect library. Made by [willemk](https://github.com/willemk). +* [mobiledetect2vcl](https://github.com/carlosabalde/mobiledetect2vcl) - Python script to transform the Mobile +Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache +configuration. Made by [Carlos Abalde](https://github.com/carlosabalde). + +**LUA** + +* [mobile-detect.lua](https://github.com/yourpalmark/mobile-detect.lua) is a port of Mobile-Detect to Lua for +NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side +mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included). +Made by [Mark Walters](https://github.com/yourpalmark). + +**PHP** + +**WordPress** + +* [Mobile Detect for WordPress](https://wordpress.org/plugins/tinywp-mobile-detect/) - WordPress has a built-in function +(`wp_is_mobile()`) to detect mobile devices. There is (at least) one catch, though. It considers iPad (iPad pro, +and any tablet) as a mobile. So, this 3rd party module changes the way `wp_is_mobile()` works with the help of +Mobile Detect PHP library! +Made by [Pothi Kalimuthu](https://github.com/pothi) + +* [WordPress Mobile Detect](https://wordpress.org/plugins/wp-mobile-detect/) - Gives you the ability to wrap that +infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will +decide to show that content only if the user is NOT on a phone or tablet. +Made by [Jesse Friedman](https://profiles.wordpress.org/professor44/). + +* [mobble](https://wordpress.org/plugins/mobble/) - provides mobile related conditional functions for your site. +e.g. `is_iphone()`, `is_mobile()` and `is_tablet()`. Made by Scott Evans. + +* [WordPress Responsage](https://github.com/iamspacehead/responsage) - A small WordPress theme plugin that allows +you to make your images responsive. Made by [Adrian Ciaschetti](https://github.com/iamspacehead). + +* [WP247 Body Classes](https://wordpress.org/plugins/wp247-body-classes/) - Add unique classes to the `body` tag for +easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions. +Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile, +.is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser. +Made by [wescleveland56](https://github.com/wescleveland56). + +* [Adaptive Content](https://wordpress.org/plugins/addfunc-adaptive-content/) for WordPress provides the most +intuitive set of shortcodes for including/excluding content on mobile devices, tablets desktops and other +more specific device parameters. This lightweight plugin lets content writers and theme authors choose when +WordPress should or shouldn’t show any give content item using shortcodes and quicktags or theme elements using functions. +Made by [AddFunc](https://profiles.wordpress.org/addfunc). + +* [AddFunc Mobile Detect](https://wordpress.org/plugins/addfunc-mobile-detect/) for WordPress redirects +mobile traffic to your mobile website and, basically, gives you loads of control over your mobile redirects. +Made by [AddFunc](https://profiles.wordpress.org/addfunc). + +**Drupal** + +* [Drupal Mobile Switch](https://www.drupal.org/project/mobile_switch) - The Mobile Switch Drupal module provides a +automatic theme switch functionality for mobile devices, detected by Browscap or Mobile Detect. +Made by [Siegfried Neumann](https://www.drupal.org/user/45267). + +* [Drupal Context Mobile Detect](https://www.drupal.org/project/context_mobile_detect) - This is a Drupal context module +which integrates Context and PHP Mobile Detect library. +Created by [Artem Shymko](https://www.drupal.org/user/432492). + +* [Drupal Mobile Detect](https://www.drupal.org/project/mobile_detect) - Lightweight mobile detect module for Drupal + created by [Matthew Donadio](https://www.drupal.org/user/325244). + +**Joomla** + +* [yagendoo Joomla! Mobile Detection Plugin](http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html) - Lightweight PHP plugin for Joomla! +that detects a mobile browser using the Mobile Detect class. +Made by yagendoo media. + +* [User Agent Detector plugin](https://github.com/renekreijveld/UserAgentDetector) - This system plugin detects the user +agent of your website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the +site is running on a desktop pc, tablet or smartphone. It can also detect if the visitor is a spider bot (search engine). +Session variable that is set: `ualayout`. Possible values: desktop, tablet, mobile, bot. +Made by @ReneKreijveld. + +**Magento** + +* [Magento helper](http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/) from Optimise Web enables +the use of all functions provided by Mobile Detect. Made by [Kathir Vel](http://www.kathirvel.com). + +* [Magento 2 Mobile Detect Theme Change](https://github.com/EaDesgin/magento2-mobiledetect) is an extension for Magento 2 +that will change the theme or redirect to a different URL. Also containing a helper to check for the device type. + +**PrestaShop** + +* [PrestaShop](https://www.prestashop.com) is a free, secure and open source shopping cart platform. Mobile_Detect +is included in the default package since 1.5.x. + +**Laravel** + +* [Agent](https://github.com/jenssegers/agent) is a user agent class for Laravel based on Mobile Detect with some +additional functionality. +Made by [Jens Segers](https://github.com/jenssegers). + +* [Laravel Mobile Detect](https://github.com/riverskies/laravel-mobile-detect) is a package that enables you to use device detection right in your Laravel Blade templates. (Utilises the well-known, constantly updated PHP mobile detection library.) +Made by [Barnabas Kecskes](https://github.com/barnabaskecskes). + +* [BrowserDetect](https://github.com/hisorange/browser-detect) is a browser and mobile detection package, collects +and wrap together the best user-agent identifiers for Laravel. +Created by [Varga Zsolt](https://github.com/hisorange). + +**Zend Framework** + +* [ZF2 Mobile-Detect](https://github.com/neilime/zf2-mobile-detect.git) is a Zend Framework 2 module that provides +Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers). +Made by [neilime](https://github.com/neilime). + +* [ZF2 MobileDetectModule](https://github.com/nikolaposa/MobileDetectModule) facilitates integration of a PHP MobileDetect +class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module, +but differs in initialization and provision routine of the actual Mobile_Detect class. +Appropriate view helper and controller plugin also have different conceptions. +Made by [Nikola Posa](https://github.com/nikolaposa). + +**Symfony** + +* [Symfony3 MobileDetectBundle](https://github.com/tattali/MobileDetectBundle) is a Symfony bundle to detect mobile devices, manage mobile view and redirect to the mobile and tablet version. Made by [Théo Attali](https://github.com/tattali). + +* [Symfony2 Mobile Detect Bundle](https://github.com/suncat2000/MobileDetectBundle) is a bundle for detecting mobile devices, +manage mobile view and redirect to the mobile and tablet version. +Made by [Nikolay Ivlev](https://github.com/suncat2000). + +* [Silex Mobile Detect Service Provider](https://github.com/jbinfo/MobileDetectServiceProvider) is a service provider to +interact with Mobile detect class methods. +Made by [Lhassan Baazzi](https://github.com/jbinfo). + +**Slim Framework** + +* [Slim_Mobile_Detect](https://github.com/zguillez/slim_mobile_detect) implements Mobile_Detect lib for different +responses write on Slim Framework App. + +**ExpressionEngine** + +* [EE2 Detect Mobile](https://github.com/garethtdavies/detect-mobile) is a lightweight PHP plugin for EE2 that detects + a mobile browser using the Mobile Detect class. Made by [Gareth Davies](https://github.com/garethtdavies). + +**Yii Framework** + +* [Yii Extension](https://github.com/iamsalnikov/MobileDetect) - Mobile detect plugin for Yii framework. +Made by [Alexey Salnikov](https://github.com/iamsalnikov). + +* [Yii Extension](https://github.com/candasm/yii1-mobile-detect-component) - Mobile detect component for Yii framework +1.x version which supports composer package manager. Made by [Candas Minareci](https://github.com/candasm). + +* [Yii2 Device Detect](https://github.com/alexandernst/yii2-device-detect/) - Yii2 extension for Mobile-Detect library. +Made by [Alexander Nestorov](https://github.com/alexandernst). + +**CakePHP** + +* [CakePHP MobileDetect](https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin) is a plugin component for +CakePHP 2.x. Made by [Gregory Gaskill](https://github.com/chronon). + +**FuelPHP** + +* [Special Agent](https://github.com/rob-bar/special_agent) is a FuelPHP package which uses php-mobile-detect to +determine whether a device is mobile or not. It overrides the Fuelphp Agent class its methods. +Made by [Robbie Bardjin](https://github.com/rob-bar). + + +**TYPO3** + +* [px_mobiledetect](https://typo3.org/extensions/repository/view/px_mobiledetect) is an extension that helps to detect +visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak. + +**Other** + +* [PageCache](https://github.com/mmamedov/page-cache) is a lightweight PHP library for full page cache, +with built-in Mobile-Detect support. Made by [Muhammed Mamedov](https://github.com/mmamedov). + +* [Statamic CMS Mobile Detect](https://github.com/haikulab/statamic-mobile-detect) is a plugin. +Made by [Sergei Filippov](https://github.com/haikulab/statamic-mobile-detect) of Haiku Lab. + +* [Kohana Mobile Detect](https://github.com/madeinnordeste/kohana-mobile-detect) is an example of implementation of +Mobile_Detect class with Kohana framework. +Written by [Luiz Alberto S. Ribeiro](https://github.com/madeinnordeste). + +* [MemHT](https://www.memht.com) is a Free PHP CMS and Blog that permit the creation and the management online +of websites with few and easy steps. Has the class included in the core. + +* [concrete5](https://www.concrete5.org) is a CMS that is free and open source. The library is included in the core. + +* [engine7](https://github.com/QOXCorp/exengine) is PHP Open Source Framework. The Mobile_Detect class is included in +the engine. + +* [Zikula](http://zikula.org) is a free and open-source Content Management Framework, which allows you to run +impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special +Mobile theme, using jQueryMobile. + +* [UserAgentInfo](https://github.com/quentin389/UserAgentInfo) is a PHP class for parsing user agent strings +(HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more. +Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing. +Made by [quentin389](https://github.com/quentin389). + +* [LJ Mobile Detect](https://github.com/lewisjenkins/craft-lj-mobiledetect) is a simple implementation of Mobile Detect +for Craft CMS. Made by [Lewis Jenkins](https://github.com/lewisjenkins). + +* [Detect Craft](https://github.com/mmikkel/Detect-Craft) is a Craft CMS wrapper for the Mobile_Detect library. Made by [Mikkel Rummelhoff](https://github.com/mmikkel). + +* [Grav Plugin Mobile Detect](https://github.com/dimitrilongo/grav-plugin-mobile-detect/) is a simple implementation +of Mobile Detect for Grav CMS. Made by [Dimitri Longo](https://github.com/dimitrilongo). + +* [Mobile_Detect module for UliCMS](https://github.com/derUli/ulicms-Mobile_Detect). +Made by [derUli](https://github.com/derUli). + +**Perl** + + * [MobileDetect.pm](https://www.buzzerstar.com/development/) is a Perl module for Mobile Detect. + Made by [Sebastian Enger](https://devop.tools/). + +**Python** + +* [pymobiledetect](https://pypi.python.org/pypi/pymobiledetect) - Mobile detect python package. +Made by Bas van Oostveen. + +**Ruby** + +* [mobile_detect.rb](https://github.com/ktaragorn/mobile_detect) is a Ruby gem using the JSON data exposed by the +php project and implementing a basic subset of the API (as much as can be done by the exposed data). +Made by [Karthik T](https://github.com/ktaragorn). + +**Go** + +* [GoMobileDetect](https://github.com/Shaked/gomobiledetect) is a Go port of Mobile Detect class. +Made by [https://github.com/Shaked](Shaked). + + +**LUA** + +* [ua-lua](https://github.com/robinef/ua-lua) is a small lib written in LUA providing device type detection. +ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon. +Made by [Frédéric Robinet](https://github.com/robinef). + +**.Net** + +* [mobile-detect](https://github.com/validide/mobile-detect) is a .Net partial port written in C#. +Made by [Valentin Dide](https://github.com/validide). + +**ColdFusion** + +* [MobileDetect](https://github.com/GiancarloGomez/ColdFusion-MobileDetect) is a CFC port of the +Mobile_Detect PHP Library. Made by [Giancarlo Gomez](https://github.com/GiancarloGomez). + +**Experiments** :bulb: + +* [Mobile Detect Fast](https://bitbucket.org/lanaguani/mobile-detect-fast/) (See: [#474](https://github.com/serbanghita/Mobile-Detect/issues/474)) is a class to increase the performance of Mobile Detect lib. Made by [LanaGuani](https://github.com/lanaguanifw). diff --git a/lib/vendor/mobiledetect/mobiledetectlib/composer.json b/lib/vendor/mobiledetect/mobiledetectlib/composer.json new file mode 100644 index 0000000000..97496f0b13 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/composer.json @@ -0,0 +1,31 @@ +{ + "name": "mobiledetect/mobiledetectlib", + "type": "library", + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "keywords": ["mobile", "mobile detect", "mobile detector", "php mobile detect", "detect mobile devices"], + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "license": "MIT", + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36" + }, + "autoload": { + "classmap": ["Mobile_Detect.php"], + "psr-0": { + "Detection": "namespaced/" + } + }, + "archive": { + "exclude": ["docs", "examples", "export"] + } +} diff --git a/lib/vendor/mobiledetect/mobiledetectlib/docker-compose.yml b/lib/vendor/mobiledetect/mobiledetectlib/docker-compose.yml new file mode 100644 index 0000000000..ecf0df32fe --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/docker-compose.yml @@ -0,0 +1,16 @@ +# This is for local development. NOT WORKING ATM! +# Docker image of PHP 5.3 lacks ssl module and composer requires it +# Also this image lacks git which is at some point required during installation of phpunit deps. +services: + app: + image: php:7-alpine3.16 + working_dir: /app + command: > + /bin/sh -c " + rm -rf vendor && + rm -f composer.lock composer.phar && + curl -s https://getcomposer.org/download/2.0.0/composer.phar -o composer.phar && + php composer.phar update --no-interaction --prefer-dist -vvv && + vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-text --strict-coverage --stop-on-risky" + volumes: + - .:/app \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php b/lib/vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php new file mode 100644 index 0000000000..ca7efec23f --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php @@ -0,0 +1,22 @@ + + + The PSR-2 coding standard extended. + + + + + + + + + + error + + + + + + + \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/BasicsTest.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/BasicsTest.php new file mode 100755 index 0000000000..f0496ddc19 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/BasicsTest.php @@ -0,0 +1,510 @@ +assertTrue(class_exists('Mobile_Detect')); + } + + public function setUp() + { + $this->detect = new Mobile_Detect; + } + + public function testBasicMethods() + { + $this->assertNotEmpty( $this->detect->getScriptVersion() ); + + $this->detect->setHttpHeaders(array( + 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13', + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'home.ghita.org', + 'HTTP_X_REAL_IP' => '1.2.3.4', + 'HTTP_X_FORWARDED_FOR' => '1.2.3.5', + 'HTTP_CONNECTION' => 'close', + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25', + 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01', + 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', + 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate', + 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', + 'HTTP_REFERER' => 'http://mobiledetect.net', + 'HTTP_PRAGMA' => 'no-cache', + 'HTTP_CACHE_CONTROL' => 'no-cache', + 'REMOTE_ADDR' => '11.22.33.44', + 'REQUEST_TIME' => '01-10-2012 07:57' + )); + + //12 because only 12 start with HTTP_ + $this->assertCount( 12, $this->detect->getHttpHeaders() ); + $this->assertTrue( $this->detect->checkHttpHeadersForMobile() ); + + $this->detect->setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25'); + $this->assertNotEmpty( $this->detect->getUserAgent() ); + + $this->assertTrue( $this->detect->isMobile() ); + $this->assertFalse( $this->detect->isTablet() ); + + $this->assertTrue( $this->detect->isIphone() ); + $this->assertTrue( $this->detect->isiphone() ); + $this->assertTrue( $this->detect->isiOS() ); + $this->assertTrue( $this->detect->isios() ); + $this->assertTrue( $this->detect->is('iphone') ); + $this->assertTrue( $this->detect->is('ios') ); + + } + + public function headersProvider() + { + return array( + array(array( + 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13', + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'home.ghita.org', + 'HTTP_X_REAL_IP' => '1.2.3.4', + 'HTTP_X_FORWARDED_FOR' => '1.2.3.5', + 'HTTP_CONNECTION' => 'close', + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25', + 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01', + 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', + 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate', + 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', + 'HTTP_REFERER' => 'http://mobiledetect.net', + 'HTTP_PRAGMA' => 'no-cache', + 'HTTP_CACHE_CONTROL' => 'no-cache', + 'REMOTE_ADDR' => '11.22.33.44', + 'REQUEST_TIME' => '01-10-2012 07:57' + )), + array(array( + 'SERVER_SOFTWARE' => 'Rogue software', + 'REQUEST_METHOD' => 'GET', + 'REMOTE_ADDR' => '8.8.8.8', + 'REQUEST_TIME' => '07-10-2013 23:56', + 'HTTP_USER_AGENT' => "garbage/1.0" + )), + array(array( + 'SERVER_SOFTWARE' => 'Apache/1.3.17 (Linux) PHP/5.5.2', + 'REQUEST_METHOD' => 'HEAD', + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Linux; U; Android 1.5; en-us; ADR6200 Build/CUPCAKE) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1', + 'REMOTE_ADDR' => '1.250.250.0', + 'REQUEST_TIME' => '06-12-2006 11:06' + )), + ); + } + + /** + * @dataProvider headersProvider + * @param array $headers + */ + public function testConstructorInjection(array $headers) + { + $md = new Mobile_Detect($headers); + + foreach ($headers as $header => $value) { + if (substr($header, 0, 5) !== 'HTTP_') { + //make sure it wasn't set + $this->assertNull($md->getHttpHeader($value)); + } else { + //make sure it's equal + $this->assertEquals($value, $md->getHttpHeader($header)); + } + } + + //verify some of the headers work with the translated getter + $this->assertNull($md->getHttpHeader('Remote-Addr')); + $this->assertNull($md->getHttpHeader('Server-Software')); + $this->assertEquals($headers['HTTP_USER_AGENT'], $md->getHttpHeader('User-Agent')); + } + + /** + * @dataProvider headersProvider + * @param $headers + */ + public function testInvalidHeader($headers) + { + $md = new Mobile_Detect($headers); + $this->assertNull($md->getHttpHeader('garbage_is_Garbage')); + } + + public function userAgentProvider() + { + return array( + array(array( + 'HTTP_USER_AGENT' => 'blah' + ), 'blah'), + array(array( + 'HTTP_USER_AGENT' => 'iphone', + 'HTTP_X_OPERAMINI_PHONE_UA' => 'some other stuff' + ), 'iphone some other stuff'), + array(array( + 'HTTP_X_DEVICE_USER_AGENT' => 'hello world' + ), 'hello world'), + array(array(), null) + ); + } + + /** + * @dataProvider userAgentProvider + * @param $headers + * @param $expectedUserAgent + */ + public function testGetUserAgent($headers, $expectedUserAgent) + { + $md = new Mobile_Detect($headers); + $md->setUserAgent(); + $this->assertSame($expectedUserAgent, $md->getUserAgent()); + } + + /** + * Headers should be reset when you use setHttpHeaders. + * @issue #144 + */ + public function testSetHttpHeaders() + { + $header1 = array('HTTP_PINK_PONY' => 'I secretly love ponies >_>'); + $md = new Mobile_Detect($header1); + $this->assertSame($md->getHttpHeaders(), $header1); + + $header2 = array('HTTP_FIRE_BREATHING_DRAGON' => 'yeah!'); + $md->setHttpHeaders($header2); + $this->assertSame($md->getHttpHeaders(), $header2); + } + + /** + * Read response from cloudfront, if the cloudfront headers are detected + */ + public function testSetCfHeaders() + { + // Test mobile detected + $header1 = array( + 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'false', + 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'true', + 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'false' + ); + $md = new Mobile_Detect($header1); + $this->assertSame($md->getCfHeaders(), $header1); + $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); + $this->assertSame($md->isTablet(), false); + $this->assertSame($md->isMobile(), true); + + // Test neither mobile nor tablet (desktop) + $header2 = array( + 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'true', + 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'false', + 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'false' + ); + $md->setHttpHeaders($header2); + $this->assertSame($md->getCfHeaders(), $header2); + $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); + $this->assertSame($md->isTablet(), false); + $this->assertSame($md->isMobile(), false); + + // Test tablet detected + $header3 = array( + 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'false', + 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'false', + 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'true' + ); + $md->setCfHeaders($header3); + $this->assertSame($md->getCfHeaders(), $header3); + $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); + $this->assertSame($md->isTablet(), true); + $this->assertSame($md->isMobile(), false); + + // Check if the headers are cleared + $header4 = array(); + $md->setHttpHeaders($header4); + $this->assertSame($md->getCfHeaders(), $header4); + } + + public function testSetUserAgent() + { + $md = new Mobile_Detect(array()); + $md->setUserAgent('hello world'); + $this->assertSame('hello world', $md->getUserAgent()); + } + + public function testSetLongUserAgent() { + $md = new Mobile_Detect(); + $md->setUserAgent(str_repeat("a", 501)); + $this->assertEquals(strlen($md->getUserAgent()), 500); + } + + public function testSetDetectionType() + { + $md = new Mobile_Detect(array()); + + $md->setDetectionType('bskdfjhs'); + $this->assertAttributeEquals( + Mobile_Detect::DETECTION_TYPE_MOBILE, + 'detectionType', + $md + ); + + $md->setDetectionType(); + $this->assertAttributeEquals( + Mobile_Detect::DETECTION_TYPE_MOBILE, + 'detectionType', + $md + ); + + $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_MOBILE); + $this->assertAttributeEquals( + Mobile_Detect::DETECTION_TYPE_MOBILE, + 'detectionType', + $md + ); + + $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_EXTENDED); + $this->assertAttributeEquals( + Mobile_Detect::DETECTION_TYPE_EXTENDED, + 'detectionType', + $md + ); + } + + //special headers that give 'quick' indication that a device is mobile + public function quickHeadersData() + { + return array( + array(array( + 'HTTP_ACCEPT' => 'application/json; q=0.2, application/x-obml2d; q=0.8, image/gif; q=0.99, */*' + )), + array(array( + 'HTTP_ACCEPT' => 'text/*; q=0.1, application/vnd.rim.html' + )), + array(array( + 'HTTP_ACCEPT' => 'text/vnd.wap.wml', + )), + array(array( + 'HTTP_ACCEPT' => 'application/vnd.wap.xhtml+xml', + )), + array(array( + 'HTTP_X_WAP_PROFILE' => 'hello', + )), + array(array( + 'HTTP_X_WAP_CLIENTID' => '' + )), + array(array( + 'HTTP_WAP_CONNECTION' => '' + )), + array(array( + 'HTTP_PROFILE' => '' + )), + array(array( + 'HTTP_X_OPERAMINI_PHONE_UA' => '' + )), + array(array( + 'HTTP_X_NOKIA_GATEWAY_ID' => '' + )), + array(array( + 'HTTP_X_ORANGE_ID' => '' + )), + array(array( + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => '' + )), + array(array( + 'HTTP_X_HUAWEI_USERID' => '' + )), + array(array( + 'HTTP_UA_OS' => '' + )), + array(array( + 'HTTP_X_MOBILE_GATEWAY' => '' + )), + array(array( + 'HTTP_X_ATT_DEVICEID' => '' + )), + array(array( + 'HTTP_UA_CPU' => 'ARM' + )) + ); + } + + /** + * @dataProvider quickHeadersData + * @param $headers + */ + public function testQuickHeaders($headers) + { + $md = new Mobile_Detect($headers); + $this->assertTrue($md->checkHttpHeadersForMobile()); + } + + // Headers that are not mobile. + public function quickNonMobileHeadersData() + { + + return array( + array(array( + 'HTTP_UA_CPU' => 'AMD64' + )), + array(array( + 'HTTP_UA_CPU' => 'X86' + )), + array(array( + 'HTTP_ACCEPT' => 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01' + )), + array(array( + 'HTTP_REQUEST_METHOD' => 'DELETE' + )), + array(array( + 'HTTP_VIA' => '1.1 ws-proxy.stuff.co.il C0A800FA' + )), + ); + + } + + /** + * @dataProvider quickNonMobileHeadersData + * @param $headers + */ + public function testNonMobileQuickHeaders($headers) + { + $md = new Mobile_Detect($headers); + $this->assertFalse($md->checkHttpHeadersForMobile()); + } + + /** + * @expectedException BadMethodCallException + */ + public function testBadMethodCall() + { + $md = new Mobile_Detect(array()); + $md->badmethodthatdoesntexistatall(); + } + + public function versionDataProvider() + { + return array( + array( + 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', + 'Android', + '4.0.4', + 4.04 + ), + array( + 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', + 'Webkit', + '535.19', + 535.19 + ), + array( + 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', + 'Chrome', + '18.0.1025.166', + 18.01025166 + ), + array( + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.448 Mobile Safari/534.8', + 'BlackBerry', + '6.0.0.448', + 6.00448 + ), + array( + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.448 Mobile Safari/534.8', + 'Webkit', + '534.8', + 534.8 + ), + array( + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.546 Mobile Safari/534.8+', + 'BlackBerry', + '6.0.0.546', + 6.00546 + ) + ); + } + + /** + * @dataProvider versionDataProvider + */ + public function testVersionExtraction($userAgent, $property, $stringVersion, $floatVersion) + { + $md = new Mobile_Detect(array('HTTP_USER_AGENT' => $userAgent)); + $prop = $md->version($property); + + $this->assertSame($stringVersion, $prop); + + $prop = $md->version($property, 'float'); + $this->assertSame($floatVersion, $prop); + + //assert that garbage data is always === false + $prop = $md->version('garbage input is always garbage'); + $this->assertFalse($prop); + } + + public function testRules() + { + $md = new Mobile_Detect; + $count = array_sum(array( + count(Mobile_Detect::getPhoneDevices()), + count(Mobile_Detect::getTabletDevices()), + count(Mobile_Detect::getOperatingSystems()), + count(Mobile_Detect::getBrowsers()) + )); + $rules = $md->getRules(); + $this->assertCount($count, $rules); + } + + public function testRulesExtended() + { + $md = new Mobile_Detect; + $count = array_sum(array( + count(Mobile_Detect::getPhoneDevices()), + count(Mobile_Detect::getTabletDevices()), + count(Mobile_Detect::getOperatingSystems()), + count(Mobile_Detect::getBrowsers()), + count(Mobile_Detect::getUtilities()) + )); + $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_EXTENDED); + $rules = $md->getRules(); + $this->assertCount($count, $rules); + } + + public function testScriptVersion() + { + $v = Mobile_Detect::getScriptVersion(); + $formatCheck = (bool)preg_match('/^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9])?$/', $v); + + $this->assertTrue($formatCheck, "Fails the semantic version test. The version " . var_export($v, true) + . ' does not match X.Y.Z pattern'); + } + + public function crazyVersionNumbers() + { + return array( + array('2.5.6', 2.56), + array('12142.2142.412521.24.152', 12142.214241252124152), + array('6_3', 6.3), + array('4_7 /7 7 12_9', 4.777129), + array('49', 49.0), + array('2.6.x', 2.6), + array('45.6.1.x.12', 45.61) + ); + } + + /** + * @dataProvider crazyVersionNumbers + * @param $raw + * @param $expected + */ + public function testPrepareVersionNo($raw, $expected) + { + $md = new Mobile_Detect; + $actual = $md->prepareVersionNo($raw); + $this->assertSame($expected, $actual, "We expected " . var_export($raw, true) . " to convert to " + . var_export($expected, true) . ', but got ' . var_export($actual, true) . ' instead'); + } +} diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.inc.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.inc.php new file mode 100644 index 0000000000..5c4df79b9a --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.inc.php @@ -0,0 +1,27 @@ +isDot()) { + continue; + } + $listNew = include $includeBasePath . '/' . $fileInfo->getFilename(); + if (is_array($listNew)) { + $list = array_merge($list, $listNew); + } +} + +return $list; diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.pending.txt b/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.pending.txt new file mode 100644 index 0000000000..c673c8f76d --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/UA_List.pending.txt @@ -0,0 +1,1242 @@ + req / hits / tag (444758 / 73555 / 44678) - user_agent (1041) +58989 / 6933 / 5240 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0) +55308 / 9884 / 7995 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 +36138 / 1681 / 1819 - Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.15 +25387 / 4668 / 3863 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 +23850 / 4623 / 3909 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0 +17258 / 1634 / 1391 - Mozilla/5.0 (Windows NT 6.1; rv:20.0) Gecko/20100101 Firefox/20.0 + 9315 / 1535 / 1304 - Mozilla/5.0 (X11; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0 + 7146 / 1271 / 1121 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 + 6559 / 1234 / 991 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 + 5639 / 1297 / 863 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0 + 5448 / 0 / 0 - msnbot-media/1.1 ( http://search.msn.com/msnbot.htm) + 5320 / 563 / 700 - Opera/9.80 (Windows NT 6.2; WOW64; MRA 6.0 (build 6011)) Presto/2.12.388 Version/12.15 + 4948 / 910 / 593 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0) + 4719 / 78 / 75 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1) + 4318 / 278 / 208 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E) + 4162 / 2554 / 3 - Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html) + 4140 / 903 / 919 - Mozilla/5.0 (Windows NT 6.2; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0 + 3864 / 344 / 333 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 3812 / 807 / 11 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 3799 / 563 / 496 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31 + 3251 / 601 / 629 - Opera/9.80 (Windows NT 6.1; Win64; x64) Presto/2.12.388 Version/12.15 + 3202 / 0 / 0 - Mozilla/5.0 (compatible; YandexImages/3.0; http://yandex.com/bots) + 3129 / 738 / 131 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1106.241 YaBrowser/1.5.1106.241 Safari/537.4 + 3105 / 491 / 370 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22 + 3039 / 350 / 346 - Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.15 + 3038 / 2351 / 0 - Mozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm) + 2971 / 392 / 399 - Opera/9.80 (Windows NT 6.2; WOW64) Presto/2.12.388 Version/12.15 + 2766 / 147 / 172 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.229 Version/11.60 + 2764 / 739 / 17 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 + 2650 / 2044 / 0 - Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7 (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) + 2514 / 304 / 262 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 2500 / 306 / 134 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) + 2494 / 250 / 256 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.15 + 2478 / 362 / 331 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0 + 2433 / 378 / 299 - Mozilla/5.0 (Windows NT 5.1; rv:20.0) Gecko/20100101 Firefox/20.0 + 2369 / 234 / 127 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0 + 2269 / 488 / 348 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22 + 2137 / 405 / 256 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; 1A820D29-8445-92BE-2384-712BBCEDFDB1; MRSPUTNIK 2, 4, 1, 12; BTRS124447; GTB7.4; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727; AskTbFXTV5/5.8.0.12304) + 2050 / 391 / 464 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; .NET4.0C; .NET4.0E) + 1937 / 1676 / 0 - Mozilla/5.0 (compatible; YandexBot/3.0; http://yandex.com/bots) + 1900 / 0 / 0 - Googlebot-Image/1.0 + 1894 / 289 / 299 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.70 Safari/537.17 + 1842 / 335 / 157 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 1836 / 354 / 298 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 1829 / 176 / 171 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0) + 1608 / 260 / 181 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0) + 1594 / 273 / 195 - Opera/9.80 (X11; Linux x86_64) Presto/2.12.388 Version/12.14 + 1543 / 1408 / 0 - Mozilla/5.0 (compatible; SearchBot) + 1511 / 176 / 115 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 + 1496 / 248 / 217 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31 + 1403 / 174 / 158 - Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 + 1299 / 203 / 173 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Iron/25.0.1400.0 Chrome/25.0.1400.0 Safari/537.22 + 1220 / 206 / 207 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.70 Safari/537.17 YE + 1219 / 209 / 211 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0 + 1210 / 81 / 80 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.6; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0) + 1136 / 173 / 139 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/11.04 Chromium/18.0.1025.151 Chrome/18.0.1025.151 Safari/535.19 + 1125 / 194 / 158 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22 + 1068 / 173 / 130 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5680)) Presto/2.12.388 Version/12.13 + 1040 / 202 / 207 - Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Firefox/21.0 + 1032 / 206 / 176 - Opera/9.80 (Windows NT 6.1; WOW64; U; Edition Next; ru) Presto/2.11.310 Version/12.50 + 1008 / 278 / 180 - Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + 941 / 153 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 929 / 181 / 88 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 + 896 / 148 / 44 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 893 / 213 / 3 - Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0 + 840 / 165 / 62 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.160 Safari/537.22 + 825 / 143 / 67 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; InfoPath.2; .NET CLR 2.0.50727) + 821 / 170 / 85 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 + 793 / 55 / 37 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; GTB7.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; eSobiSubscriber 2.0.4.16; .NET4.0C) + 781 / 183 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 770 / 125 / 32 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.14 + 757 / 0 / 0 - contype + 755 / 159 / 94 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 + 742 / 81 / 22 - Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14 + 709 / 180 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0 + 702 / 201 / 204 - Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 696 / 106 / 116 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 685 / 76 / 21 - Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3 + 667 / 149 / 265 - Mozilla/5.0 (X11; Linux i686; rv:10.0.2) Gecko/20100101 Firefox/10.0.2 + 648 / 51 / 49 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.6.30 Version/10.60 + 645 / 175 / 20 - Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0 + 643 / 87 / 86 - Opera/9.80 (Windows NT 6.1; WOW64; Edition Yx) Presto/2.12.388 Version/12.15 + 642 / 59 / 59 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.54 + 642 / 122 / 124 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20100101 Firefox/21.0 + 603 / 69 / 50 - Opera/9.80 (Windows NT 6.2; WOW64) Presto/2.12.388 Version/12.12 + 596 / 64 / 0 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/0.0.5; http://flipboard.com/browserproxy) + 593 / 30 / 39 - Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.289 Version/12.02 + 589 / 72 / 14 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MAAU; InfoPath.1) + 562 / 93 / 83 - Mozilla/5.0 (X11; Linux x86_64; rv:10.0.12) Gecko/20100101 Firefox/10.0.12 Iceweasel/10.0.12 + 557 / 98 / 24 - Opera/9.80 (X11; Linux x86_64) Presto/2.12.388 Version/12.15 + 545 / 108 / 137 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:20.0) Gecko/20100101 Firefox/20.0 + 532 / 87 / 62 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.28 Safari/537.31 + 519 / 280 / 0 - SolomonoBot/1.04 (http://www.solomono.ru) + 518 / 106 / 69 - Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.13 + 518 / 95 / 28 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.46 Safari/537.31 + 506 / 55 / 16 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C) + 476 / 66 / 67 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.29.13 (KHTML, like Gecko) Version/6.0.4 Safari/536.29.13 + 437 / 61 / 18 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.15 + 435 / 0 / 0 - Mozilla/5.0 (compatible) Feedfetcher-Google; ( http://www.google.com/feedfetcher.html) + 434 / 56 / 51 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.14 + 431 / 28 / 29 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 4, 1, 110; chromeframe/26.0.1410.64; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1; InfoPath.2) + 431 / 422 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google ( https://developers.google.com/ /web/snippet/) + 426 / 62 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 422 / 62 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 (.NET CLR 3.5.30729) + 417 / 56 / 21 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.12 + 401 / 64 / 64 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.65 Safari/537.36 + 400 / 387 / 0 - Mozilla/5.0 (compatible; Linux i686; Yandex.Gazeta Bot/1.0; http://gazeta.yandex.ru) + 397 / 85 / 60 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0 Iceweasel/20.0 + 387 / 50 / 49 - Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20100101 Firefox/21.0 + 379 / 71 / 0 - Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.11 + 368 / 40 / 41 - Mozilla/5.0 (Windows NT 5.1; rv:20.0) Gecko/20100101 Firefox/20.0 SeaMonkey/2.17.1 + 367 / 47 / 33 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 + 366 / 24 / 24 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.1) + 366 / 85 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0 + 360 / 60 / 30 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; DefView) + 359 / 17 / 17 - Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1212030820) Presto/2.11.355 Version/12.10 + 356 / 60 / 48 - Mozilla/5.0 (Linux; U; Android 2.2; ru-ru; HTC_Gratia_A6380 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 355 / 18 / 20 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 352 / 51 / 49 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 CoolNovo/2.0.7.11 + 348 / 74 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 340 / 47 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 8.0 (build 6007)) Presto/2.12.388 Version/12.14 + 340 / 95 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0 + 333 / 58 / 59 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1106.241 YaBrowser/1.5.1106.241 Safari/537.4 + 311 / 21 / 16 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 310 / 30 / 39 - Mozilla/5.0 (Linux; Android 4.0.4; HTC Incredible S Build/IMM76D) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 308 / 47 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1 + 306 / 18 / 0 - facebookexternalhit/1.1 ( http://www.facebook.com/externalhit_uatext.php) + 305 / 20 / 21 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 304 / 65 / 62 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5 + 303 / 293 / 0 - Mozilla/5.0 (compatible; Linux x86_64; Mail.RU_Bot/2.0; http://go.mail.ru/help/robots) + 302 / 76 / 0 - Microsoft-WebDAV-MiniRedir/6.1.7601 + 300 / 88 / 29 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 + 285 / 184 / 0 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/1.1; http://flipboard.com/browserproxy) + 282 / 35 / 40 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 + 282 / 58 / 5 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.28.10 (KHTML, like Gecko) Version/6.0.3 Safari/536.28.10 + 276 / 22 / 25 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.29.13 (KHTML, like Gecko) Version/6.0.4 Safari/536.29.13 + 273 / 12 / 0 - Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.0.11) Gecko/2009061118 Fedora/3.0.11-1.fc9 Firefox/3.0.11 + 267 / 27 / 14 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11 + 261 / 75 / 12 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.50.2 (KHTML, like Gecko) Version/5.0.6 Safari/533.22.3 + 254 / 0 / 0 - Wget/1.11.4 + 253 / 21 / 14 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 250 / 24 / 14 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25 + 250 / 57 / 0 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 250 / 218 / 0 - msnbot/2.0b ( http://search.msn.com/msnbot.htm) + 244 / 0 / 0 - Googlebot/2.1 ( http://www.google.com/bot.html) + 240 / 25 / 33 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mozart T8698) + 238 / 132 / 23 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 + 233 / 63 / 39 - Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0 + 232 / 12 / 11 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 228 / 29 / 34 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 + 219 / 34 / 10 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.12 + 219 / 26 / 2 - Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0 + 216 / 41 / 45 - Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20130415 Firefox/22.0 + 214 / 16 / 14 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; XBLWP7; ZuneWP7) + 214 / 49 / 19 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 214 / 24 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 213 / 13 / 14 - Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.2.24) Gecko/20111109 CentOS/3.6.24-3.el6.centos Firefox/3.6.24 + 207 / 26 / 26 - Mozilla/5.0 (Windows NT 6.2; rv:21.0) Gecko/20100101 Firefox/21.0 + 206 / 38 / 69 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; MRSPUTNIK 2, 4, 0, 504; GTB7.4; BTRS99144; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; OfficeLiveConnector.1.3; OfficeLivePatch.0.0; InfoPath.2; Zune 4.7) + 203 / 23 / 23 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 5.9 (build 4947)) Presto/2.12.388 Version/12.15 + 202 / 78 / 1 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch) + 201 / 60 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10 + 199 / 11 / 13 - Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; HTC Sensation Z710e Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 197 / 93 / 0 - Mozilla/5.0 (compatible; Butterfly/1.0; http://labs.topsy.com/butterfly/) Gecko/2009032608 Firefox/3.0.8 + 197 / 41 / 42 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 193 / 59 / 6 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; MS-RTC LM 8; BRI/2; .NET4.0E) + 193 / 13 / 12 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) + 193 / 11 / 12 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11 + 186 / 45 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 185 / 154 / 0 - SAMSUNG-SGH-E250/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Browser/6.2.3.3.c.1.101 (GUI) MMP/2.0 (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) + 184 / 43 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0 + 184 / 6 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 + 184 / 14 / 13 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.47 Safari/535.11 MRCHROME + 183 / 61 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.changedetection.com/bot.html ) + 182 / 15 / 15 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.229 Version/11.64 + 182 / 13 / 15 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1106.241 YaBrowser/1.5.1106.241 Safari/537.4 + 179 / 8 / 9 - Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0 + 178 / 31 / 23 - Opera/9.80 (Windows NT 6.1; Edition Yx) Presto/2.12.388 Version/12.15 + 178 / 24 / 27 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25 + 177 / 17 / 18 - Opera/9.80 (Android 4.0.3; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 177 / 31 / 33 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Comodo_Dragon/15.0.3.0 Chrome/15.0.874.102 Safari/535.2 + 176 / 43 / 45 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Iron/19.0.1100.0 Chrome/19.0.1100.0 Safari/536.5 + 175 / 148 / 0 - DoCoMo/2.0 N905i(c100;TB;W24H16) (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) + 175 / 35 / 12 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 174 / 19 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) + 172 / 52 / 0 - Opera/9.80 (Windows NT 6.0; U; en) Presto/2.10.289 Version/12.02 + 170 / 21 / 32 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7 + 170 / 27 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0 + 170 / 25 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MALC) + 167 / 27 / 30 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0 + 167 / 33 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E) + 165 / 9 / 9 - Mozilla/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25 + 164 / 19 / 0 - Mozilla/5.0 (Windows NT 6.0; rv:17.0) Gecko/20100101 Firefox/17.0 + 163 / 19 / 1 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9300 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 162 / 54 / 2 - Opera/9.80 (Windows NT 6.1; Win64; x64) Presto/2.12.388 Version/12.14 + 158 / 21 / 13 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0 + 156 / 39 / 11 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.28.10 (KHTML, like Gecko) Version/6.0.3 Safari/536.28.10 + 155 / 18 / 8 - Opera/9.80 (Android 4.0.4; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 154 / 50 / 1 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1106.241 YaBrowser/1.5.1106.241 Safari/537.4 + 150 / 27 / 14 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17 + 150 / 5 / 6 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:21.0) Gecko/20100101 Firefox/21.0 + 148 / 27 / 1 - Mozilla/5.0 (Windows NT 6.0; rv:19.0) Gecko/20100101 Firefox/19.0 + 145 / 26 / 9 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 + 143 / 32 / 4 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; BOIE9;RURU) + 142 / 13 / 11 - Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 + 142 / 121 / 1 - Java/1.7.0_21 + 140 / 16 / 3 - Mozilla/5.0 (Windows NT 6.0; rv:20.0) Gecko/20100101 Firefox/20.0 + 140 / 18 / 3 - Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20100101 Firefox/12.0 + 140 / 9 / 13 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; HTC_Sensation_Z710e; ru-ru) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 + 139 / 12 / 0 - Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.14) Gecko/2009090216 Ubuntu/9.04 (jaunty) Firefox/3.0.14 + 134 / 16 / 18 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.57 Safari/537.1 + 134 / 0 / 0 - Evernote Clip Resolver + 132 / 30 / 8 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20130409 Firefox/20.0 + 132 / 17 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 + 132 / 38 / 0 - Wget/1.13.4 (linux-gnu) + 132 / 35 / 0 - Opera/9.80 (Windows NT 6.1; Edition Yx) Presto/2.12.388 Version/12.14 + 132 / 13 / 15 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 132 / 113 / 0 - Mozilla/5.0 (compatible; Mail.RU_Bot/2.0; http://go.mail.ru/help/robots) + 131 / 41 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.229 Version/11.62 + 131 / 15 / 1 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729; .NET4.0E) + 131 / 103 / 0 - UnwindFetchor/1.0 ( http://www.gnip.com/) + 130 / 27 / 19 - Opera/9.63 (Windows NT 6.0; U; ru) Presto/2.1.1 + 128 / 9 / 12 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 + 128 / 62 / 1 - - + 126 / 0 / 50 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534 (KHTML, like Gecko) BingPreview/1.0b + 124 / 14 / 19 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E) + 122 / 25 / 2 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; InfoPath.1) + 121 / 58 / 0 - Mozilla/5.0 (compatible; Ezooms/1.0; ezooms.bot@gmail.com) + 121 / 3 / 3 - Opera/9.80 (Android; Opera Mini/6.5.27452/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 120 / 24 / 9 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1 + 120 / 5 / 6 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9100 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 119 / 17 / 19 - Opera/9.80 (Windows NT 6.1; MRA 5.9 (build 4953)) Presto/2.12.388 Version/12.15 + 118 / 46 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; InfoPath.3) + 118 / 35 / 8 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11 + 117 / 23 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 116 / 20 / 24 - Mozilla/5.0 (X11; SunOS i86pc; rv:10.0.4) Gecko/20100101 Firefox/10.0.4 + 115 / 6 / 2 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.4 (KHTML, like Gecko; Google Web Preview) Chrome/22.0.1229 Safari/537.4 + 115 / 17 / 16 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22 + 112 / 9 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 111 / 15 / 17 - Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 111 / 13 / 16 - Opera/9.80 (Windows NT 6.0; MRA 5.5 (build 02842)) Presto/2.12.388 Version/12.14 + 110 / 61 / 0 - Mozilla/5.0 (compatible; TourlentaScanner/0.6; http://tourlenta.com) + 110 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; InfoPath.1; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 108 / 15 / 3 - Mozilla/5.0 (Windows NT 5.1; rv:10.0) Gecko/20100101 Firefox/10.0 + 107 / 40 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_1) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25 + 104 / 11 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko/20100101 Firefox/11.0 + 104 / 13 / 13 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 104 / 41 / 1 - Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 103 / 80 / 0 - NING/1.0 + 103 / 16 / 12 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9100 Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 103 / 30 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1106.240 YaBrowser/1.5.1106.240 Safari/537.4 + 102 / 12 / 15 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7 + 101 / 17 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.12 Safari/537.36 + 101 / 14 / 2 - Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0 + 101 / 15 / 16 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.2; .NET4.0C; .NET4.0E) + 98 / 2 / 2 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.21 (KHTML, like Gecko) QupZilla/1.4.3 Safari/537.21 + 98 / 9 / 8 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 96 / 14 / 5 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; InfoPath.1; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 95 / 26 / 2 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.00 + 94 / 21 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 + 93 / 22 / 22 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; AskTbAVR-3/5.15.11.30498) + 92 / 36 / 36 - Mozilla/5.0 (X11; Linux x86_64; rv:21.0) Gecko/20100101 Firefox/21.0 + 92 / 17 / 0 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.10.229 Version/11.62 + 92 / 23 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; MRSPUTNIK 2, 4, 1, 162; MRA 5.5 (build 02842); SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.30729) + 91 / 12 / 13 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800) + 91 / 15 / 19 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.10 + 89 / 1 / 1 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 CoolNovo/2.0.7.11 + 88 / 17 / 20 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A8426 Safari/8536.25 + 88 / 45 / 0 - Mozilla/5.0 (compatible; vkShare; http://vk.com/dev/Share) + 88 / 12 / 15 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 YaBrowser/1.7.1364.12390 Safari/537.22 + 87 / 24 / 24 - Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.11 + 87 / 11 / 12 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5976)) Presto/2.12.388 Version/12.15 + 85 / 3 / 0 - Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:24.0) Gecko/20130525 Firefox/24.0 + 85 / 2 / 2 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MDDC; InfoPath.3; .NET4.0C) + 84 / 5 / 5 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0 + 83 / 27 / 8 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.70 Safari/537.17 YE + 82 / 10 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0 + 81 / 16 / 0 - Mozilla/5.0 (X11; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0 + 81 / 9 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) + 81 / 2 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 81 / 6 / 8 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30; .NET4.0C; .NET4.0E) + 80 / 9 / 9 - Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0 + 79 / 11 / 0 - Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B206 + 78 / 4 / 4 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Safari/537.22 + 78 / 20 / 21 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/534.24 + 78 / 26 / 0 - Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 76 / 8 / 14 - Opera/9.80 (Windows NT 6.1; WOW64; Edition Rambler) Presto/2.12.388 Version/12.15 + 75 / 56 / 0 - Mozilla/5.0 (compatible; MJ12bot/v1.4.3; http://www.majestic12.co.uk/bot.php? ) + 74 / 18 / 19 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0) + 74 / 5 / 13 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 74 / 9 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5 (.NET CLR 3.5.30729) + 74 / 4 / 1 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.289 Version/12.02 + 74 / 6 / 4 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 74 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRSPUTNIK 2, 2, 0, 94; GTB7.4; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 73 / 8 / 8 - Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920) + 72 / 40 / 0 - Mozilla/5.0 (compatible; YandexDirect/3.0; http://yandex.com/bots) + 71 / 24 / 5 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MASMJS) + 70 / 2 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.47 Safari/535.11 MRCHROME + 70 / 24 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 4, 0, 484; MRA 6.0 (build 5970); .NET4.0E; AskTbFXTV5/5.14.1.20007; .NET4.0C) + 70 / 11 / 0 - Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp) + 69 / 6 / 8 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 69 / 5 / 8 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 5.10 (build 5282)) Presto/2.12.388 Version/12.15 + 69 / 4 / 5 - Opera/9.80 (Android; Opera Mini/7.5.33286/29.3345; U; en) Presto/2.8.119 Version/11.10 + 67 / 15 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Media Center PC 6.0; BRI/2; InfoPath.3) + 67 / 10 / 8 - Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0.1 + 67 / 17 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.36 YaBrowser/2.0.1364.6141 Safari/537.22 + 67 / 11 / 7 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 67 / 3 / 3 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) + 65 / 6 / 1 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0 + 65 / 8 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:16.0; Avant TriCore) Gecko/20121105 Firefox/16.0 + 64 / 16 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31 + 64 / 5 / 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.53 Mobile/10B329 Safari/8536.25 + 64 / 9 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 + 64 / 4 / 6 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.69 Safari/537.17 + 63 / 6 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 63 / 6 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0 Iceweasel/18.0.1 + 63 / 0 / 0 - Microsoft Office Existence Discovery + 63 / 2 / 5 - Mozilla/5.0 (Linux; U; Android 2.3.5; en-ru; HTC_DesireS_S510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 63 / 10 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB7.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 63 / 7 / 12 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 6081)) Presto/2.12.388 Version/12.15 + 62 / 43 / 0 - ia_archiver ( http://www.alexa.com/site/help/webmasters; crawler@alexa.com) + 60 / 17 / 0 - Opera/9.80 (Windows NT 5.2; Edition Yx) Presto/2.12.388 Version/12.14 + 60 / 0 / 0 - Opera/9.80 (Series 60; Opera Mini/7.0.29482/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 59 / 3 / 4 - Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.22296/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 58 / 0 / 2 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 58 / 6 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; InfoPath.2; .NET4.0E) + 57 / 5 / 5 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.12 Safari/537.36 + 57 / 7 / 0 - Mozilla/5.0 (Linux; Android 4.0.4; ZTE Grand Era Build/IMM76L) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.40 Mobile Safari/537.31 OPR/14.0.1074.54070 + 57 / 5 / 7 - Mozilla/5.0 (Linux; Android 4.0.4; U8836D Build/HuaweiU8836D) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 56 / 3 / 4 - Opera/9.80 (Windows NT 6.1; Edition Yx 01) Presto/2.12.388 Version/12.14 + 56 / 4 / 4 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X; ru-ru) AppleWebKit/535 (KHTML, like Gecko) Version/5.0 Safari/535.18 Midori/0.4 + 55 / 11 / 1 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 55 / 13 / 14 - Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 54 / 4 / 4 - Opera/9.80 (Windows NT 6.1; Edition Yx 01) Presto/2.12.388 Version/12.11 + 54 / 35 / 0 - ichiro/3.0 (http://search.goo.ne.jp/option/use/sub4/sub4-1/) + 54 / 20 / 0 - Microsoft-WebDAV-MiniRedir/6.1.7600 + 54 / 5 / 7 - Mozilla/5.0 (Linux; U; Android 2.2.1; ru-ru; HTC Wildfire Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 53 / 18 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1 + 53 / 2 / 3 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 53 / 10 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31 + 53 / 9 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 + 52 / 2 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 CoolNovo/2.0.6.12 + 52 / 5 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0 SeaMonkey/2.16.2 + 52 / 2 / 4 - Opera/9.80 (Windows NT 6.2; WOW64; YZF) Presto/2.12.388 Version/12.15 + 52 / 8 / 0 - Mozilla/5.0 (Linux; U; Android 3.2; ru-ru; GT-P7300 Build/HTJ85B) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 + 51 / 12 / 18 - Opera/9.80 (Windows NT 5.1; WOW64) Presto/2.12.388 Version/12.14 + 51 / 11 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0 + 51 / 41 / 0 - Mozilla/5.0 (compatible; TweetedTimes Bot/1.0; http://tweetedtimes.com) + 51 / 7 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0) + 51 / 5 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; LG-E510 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 49 / 12 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.14 (KHTML, like Gecko) Version/6.0.1 Safari/536.26.14 + 49 / 4 / 4 - Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B176 + 48 / 4 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30) + 47 / 11 / 3 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.36 YaBrowser/2.0.1364.6141 Safari/537.22 + 47 / 39 / 0 - Wotbox/2.01 ( http://www.wotbox.com/bot/) + 47 / 4 / 4 - Mozilla/5.0 (X11; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 46 / 12 / 2 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0 + 46 / 4 / 5 - Opera/9.80 (Windows NT 6.1; MRA 5.10 (build 5310)) Presto/2.12.388 Version/12.14 + 45 / 3 / 4 - Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 45 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22 + 44 / 8 / 8 - Opera/9.80 (X11; Linux i686; U; en) Presto/2.10.289 Version/12.02 + 43 / 0 / 0 - Microsoft Office Protocol Discovery + 43 / 1 / 2 - Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120714 Iceweasel/3.5.16 (like Firefox/3.5.16) + 43 / 10 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/25.0.1364.124 Mobile/10B329 Safari/8536.25 + 42 / 5 / 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25 + 42 / 3 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2) + 42 / 9 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0 + 42 / 40 / 0 - Mozilla/5.0 (compatible; Genieo/1.0 http://www.genieo.com/webfilter.html) + 41 / 2 / 4 - Mozilla/5.0 (Linux; Android 4.0.4; ZTE Grand Era Build/IMM76L) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 40 / 5 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:17.0) Gecko/20100101 Firefox/17.0 + 40 / 19 / 0 - rogerbot/1.0 (http://www.seomoz.org/dp/rogerbot, rogerbot-crawler shiny@seomoz.org) + 40 / 4 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; SP-A20i Build/MF_ICS_02.19) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 40 / 0 / 0 - Mozilla/5.0 (compatible; YandexImageResizer/2.0; http://yandex.com/bots) + 40 / 9 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; SonyEricssonLT26w Build/6.1.A.2.55) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 40 / 1 / 1 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3530; U; en) Presto/2.8.119 Version/11.10 + 40 / 13 / 13 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1 + 40 / 4 / 5 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MAAU) + 39 / 19 / 0 - Twitterbot/1.0 + 38 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; chromeframe/26.0.1410.64; EasyBits GO v1.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 37 / 4 / 0 - Opera/9.80 (Android; Opera Mini/7.0.29733/29.3271; U; en) Presto/2.8.119 Version/11.10 + 37 / 16 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25 + 37 / 3 / 4 - Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B208 Safari/7534.48.3 + 37 / 11 / 14 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/10.04 Chromium/18.0.1025.168 Chrome/18.0.1025.168 Safari/535.19 + 37 / 4 / 4 - Mozilla/5.0 (Linux; Android 4.0.4; ST26i Build/11.0.A.3.18) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 37 / 1 / 0 - Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 36 / 16 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729) + 36 / 3 / 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3 + 36 / 2 / 4 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9300 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 36 / 4 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 35 / 6 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 sputnik 2.5.3.53 + 35 / 3 / 4 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; MASMJS) + 35 / 9 / 5 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Ubuntu Chromium/24.0.1312.56 Chrome/24.0.1312.56 Safari/537.17 + 35 / 4 / 7 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.56 Safari/537.36 + 34 / 2 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31 + 34 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2 + 33 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:18.0) Gecko/20130119 Firefox/18.0 + 33 / 3 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B141 Safari/8536.25 + 33 / 2 / 5 - Mozilla/5.0 (Linux; Android 4.0.3; HUAWEI MediaPad Build/HuaweiMediaPad) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 33 / 3 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 32 / 4 / 0 - Mozilla/5.0 (Linux; Android 4.1.2; ST26i Build/11.2.A.0.21) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 32 / 4 / 6 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; InfoPath.1; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 32 / 2 / 6 - Mozilla/5.0 (Android; Tablet; rv:20.0) Gecko/20.0 Firefox/20.0 + 32 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7 (via ggpht.com) + 32 / 3 / 5 - Mozilla/5.0 (Windows NT 6.1; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 + 32 / 26 / 0 - JS-Kit URL Resolver, http://js-kit.com/ + 32 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11 + 32 / 1 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.11 (KHTML, like Gecko) Ubuntu Chromium/23.0.1271.97 Chrome/23.0.1271.97 Safari/537.11 + 32 / 29 / 0 - Mozilla/5.0 (compatible; SISTRIX Crawler; http://crawler.sistrix.net/) + 32 / 27 / 0 - Mozilla/5.0 (compatible; TweetmemeBot/3.0; http://tweetmeme.com/) + 32 / 7 / 0 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.13 + 31 / 5 / 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B145 [FBAN/FBIOS;FBAV/6.0.2;FBBV/183159;FBDV/iPhone4,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/6.1.1;FBSS/2; FBCR/O2;FBID/phone;FBLC/en_US;FBOP/1] + 31 / 9 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20130403 Firefox/19.0 + 31 / 3 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 31 / 3 / 1 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 31 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 30 / 2 / 5 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; Win64; x64; Trident/4.0; Avant Browser; .NET CLR 2.0.50727) + 30 / 1 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B146 Safari/8536.25 + 30 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; OfficeLiveConnector.1.5; OfficeLivePatch.1.3; InfoPath.3; .NET4.0C; .NET4.0E; .NET CLR 3.0.04506.30; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 30 / 4 / 3 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11 + 30 / 7 / 7 - Opera/9.80 (Windows NT 6.1; WOW64; Edition Yx) Presto/2.12.388 Version/12.14 + 29 / 7 / 8 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; EVO3D_X515m Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 29 / 2 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0 + 29 / 4 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.229 Version/11.64 + 29 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E) + 29 / 5 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; HTC_DesireS_S510e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 28 / 3 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; (R1 1.6); AskTbIMB/5.9.1.14019) + 28 / 2 / 3 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22 + 28 / 0 / 4 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.10.289 Version/12.01 + 28 / 24 / 0 - Mozilla/5.0 (compatible; PaperLiBot/2.1; http://support.paper.li/entries/20023257-what-is-paper-li) + 28 / 3 / 2 - Mozilla/5.0 (Android; Tablet; rv:21.0) Gecko/21.0 Firefox/21.0 + 28 / 2 / 0 - Mozilla/5.0 (Linux; Android 4.2.2; Galaxy Nexus Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.54 Mobile Safari/537.31 + 28 / 2 / 0 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 28 / 3 / 4 - Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0 + 28 / 1 / 1 - Mozilla/5.0 (Android; Mobile; rv:20.0) Gecko/20.0 Firefox/20.0 + 27 / 21 / 1 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.11 + 27 / 2 / 0 - Opera/9.80 (Android; Opera Mini/6.5.29194/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 27 / 1 / 3 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5972)) Presto/2.12.388 Version/12.15 + 27 / 2 / 0 - Opera/9.80 (Windows NT 6.0; U; ru) Presto/2.8.131 Version/11.10 + 27 / 1 / 1 - Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.6) Gecko/20100625 MRA 5.5 (build 02842) Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0C) sputnik 2.5.0.142 + 27 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Win64; x64; Trident/6.0) + 27 / 3 / 5 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30 + 27 / 1 / 0 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I8190 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 26 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; AskTbFF/5.15.4.23821; MSOffice 12) + 26 / 2 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 + 26 / 1 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 + 26 / 4 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; BRI/2) + 26 / 20 / 0 - Mozilla/5.0 (compatible; ZumBot/1.0; http://help.zum.com/inquiry) + 26 / 7 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) rekonq Safari/534.34 + 25 / 2 / 2 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 920) + 25 / 3 / 3 - Opera/9.80 (J2ME/MIDP; Opera Mini/7.1.32052/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 25 / 6 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.28) Gecko/20120306 Firefox/3.6.28 + 25 / 2 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.40 Safari/537.31 + 25 / 2 / 2 - Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireHD_A9191 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 25 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 1.1.4322) + 25 / 1 / 4 - Mozilla/5.0 (Linux; Android 4.0.4; ST25i Build/6.1.1.B.1.10) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 25 / 12 / 2 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2) + 25 / 2 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; Liquid MT Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 25 / 2 / 2 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 25 / 4 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0 + 24 / 3 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130404 Firefox/23.0 + 24 / 4 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:19.0) Gecko/20100101 Firefox/19.0 + 24 / 0 / 0 - Wget/1.14 (linux-gnu) + 24 / 14 / 0 - Mozilla/5.0 (compatible; Baiduspider/2.0; http://www.baidu.com/search/spider.html) + 24 / 1 / 1 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 24 / 2 / 0 - Opera/9.80 (Windows NT 6.2; WOW64) Presto/2.12.388 Version/12.14 + 24 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; BRI/2) + 24 / 2 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 YB/5.1.3 + 23 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1 + 23 / 1 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; Touch) + 23 / 3 / 3 - Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0 + 22 / 1 / 0 - Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11 + 22 / 2 / 0 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.5.24 Version/10.53 + 22 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/6.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; ms-office; MSOffice 14) + 22 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) + 22 / 2 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10 + 22 / 3 / 4 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 22 / 2 / 2 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20130430 Firefox/20.0 + 22 / 2 / 2 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.28 (KHTML, like Gecko) Chrome/26.0.1397.2 Safari/537.28 + 22 / 6 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.1634 Safari/535.19 YE + 22 / 20 / 0 - MetaURI API/2.0 metauri.com + 21 / 1 / 2 - Mozilla/5.0 (Linux; Android 4.1.2; SAMSUNG-SGH-I727 Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 21 / 2 / 2 - Opera/9.80 (Android 4.1.2; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 21 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4 + 21 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.47 Safari/535.11 MRCHROME + 21 / 21 / 0 - Mozilla/3.0 (compatible; Indy Library) + 20 / 2 / 0 - Opera/9.80 (Windows NT 6.1; U; Edition Campaign 09; ru) Presto/2.9.168 Version/11.52 + 20 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; InfoPath.2; .NET CLR 3.0.30729) + 20 / 2 / 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B143 Safari/8536.25 + 20 / 3 / 5 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; SonyST26i Build/11.2.A.0.21) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 20 / 10 / 0 - Microsoft Data Access Internet Publishing Provider Protocol Discovery + 20 / 14 / 0 - curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 + 20 / 0 / 1 - Mozilla/5.0 (compatible; MSIE 10.0; AOL 9.6; AOLBuild 4340.168; Windows NT 6.1; Trident/6.0) + 19 / 1 / 0 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 19 / 1 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 19 / 3 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.4 (KHTML, like Gecko) Ubuntu/12.10 Chromium/22.0.1229.94 Chrome/22.0.1229.94 Safari/537.4 + 19 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 19 / 1 / 0 - Opera/9.80 (Windows NT 6.1; U; Edition Ukraine Local; ru) Presto/2.9.168 Version/11.52 + 19 / 0 / 1 - Opera/9.80 (Windows NT 6.1; MRA 6.0 (build 6089)) Presto/2.12.388 Version/12.15 + 19 / 0 / 0 - Mozilla/5.0 (compatible; special_archiver/3.1.1 http://www.archive.org/details/archive.org_bot) + 19 / 2 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0) + 19 / 0 / 1 - Opera/9.80 (Windows NT 5.1; Edition Rambler) Presto/2.12.388 Version/12.15 + 19 / 0 / 1 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.289 Version/12.00 + 19 / 3 / 1 - Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0 + 18 / 1 / 0 - Mozilla/5.0 (Windows NT 5.2; rv:17.0) Gecko/20100101 Firefox/17.0 + 18 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BTRS124829; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 18 / 1 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3183; U; ru) Presto/2.8.119 Version/11.10 + 18 / 3 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET CLR 1.1.4322; InfoPath.3; MS-RTC LM 8) + 18 / 2 / 2 - Mozilla/5.0 (Linux; Android 4.0.3; U9200 Build/HuaweiU9200) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 18 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 + 18 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3) + 18 / 11 / 0 - Mozilla/5.0 (compatible + 18 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 18 / 4 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C) + 18 / 1 / 1 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; NEWMAN N1 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 18 / 9 / 0 - Mozilla/5.0 (compatible; YandexFavicons/1.0; http://yandex.com/bots) + 17 / 1 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 17 / 0 / 0 - Mozilla/5.0 (Linux; Android 4.2.1; Galaxy Nexus Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 17 / 1 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 + 17 / 1 / 2 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Iron/27.0.1500.0 Chrome/27.0.1500.0 Safari/537.36 + 17 / 1 / 1 - Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2 (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2 + 17 / 1 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19 + 17 / 3 / 3 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3417; U; ru) Presto/2.8.119 Version/11.10 + 17 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2) + 17 / 1 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22 + 17 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireS_S510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 17 / 0 / 1 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11 MRCHROME + 17 / 0 / 1 - Mozilla/5.0 (X11; Linux i686; rv:10.0.11) Gecko/20100101 Firefox/10.0.11 + 17 / 0 / 1 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X; ru-ru) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.82 Mobile/10A523 Safari/7534.48.3 + 16 / 1 / 1 - Opera/9.80 (Windows NT 5.2; WOW64) Presto/2.12.388 Version/12.15 + 16 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0 AlexaToolbar/alxf-2.17 + 16 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36 + 16 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.447.0 Safari/534.2 + 16 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0; LEN2) + 16 / 3 / 0 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 16 / 1 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350) + 16 / 0 / 0 - AppEngine-Google; ( http://code.google.com/appengine; appid: s~pc-gizmos) + 16 / 1 / 3 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 16 / 0 / 1 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 + 16 / 1 / 1 - Opera/9.80 (Windows NT 6.2) Presto/2.12.388 Version/12.15 + 15 / 0 / 1 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 u01-04 + 15 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1 + 15 / 0 / 1 - Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-I8150 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 15 / 0 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20130416 Firefox/22.0 + 15 / 3 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:10.0.5) Gecko/20100101 Firefox/10.0.5 + 15 / 0 / 1 - Opera/9.80 (Android; Opera Mini/7.5.33286/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 15 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC Sensation Z710e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 15 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; IncredibleS_S710e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 15 / 1 / 1 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.20 Safari/537.36 OPR/15.0.1147.18 (Edition Next) + 15 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9070 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 15 / 1 / 0 - Mozilla/5.0 (X11; FreeBSD amd64; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 15 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 15 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 + 15 / 0 / 1 - Opera/9.80 (Windows NT 5.1; U; MRA 5.7 (build 03686); ru) Presto/2.10.289 Version/12.01 + 15 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 15 / 1 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.20 Safari/537.36 OPR/15.0.1147.18 (Edition Next) + 15 / 0 / 1 - Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 5970)) Presto/2.12.388 Version/12.15 + 14 / 1 / 3 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20130413 Firefox/20.0 + 14 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.2; .NET CLR 1.1.4322; MS-RTC LM 8) + 14 / 1 / 1 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5 Nichrome/self/19 + 14 / 1 / 0 - Mozilla/5.0 (Linux; Android 4.1.1; GT-N8000 Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 14 / 1 / 1 - Opera/9.80 (J2ME/MIDP; Opera Mini/4.1.13907/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 14 / 6 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1 + 14 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S5830i Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 14 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Tablet PC 2.0; MASMJS) + 14 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BTRS126674; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322) + 14 / 14 / 0 - W3C_Validator/1.3 http://validator.w3.org/services + 14 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-I9001 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 14 / 2 / 2 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3594; U; ru) Presto/2.8.119 Version/11.10 + 14 / 0 / 0 - Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20110328 Firefox/6.0.2 + 14 / 1 / 1 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1485.0 Safari/537.36 + 14 / 1 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.65 Safari/537.36 + 14 / 2 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1 WebMoney Advisor MRA 5.7 (build 03796); + 14 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; DefView; .NET4.0C; Tablet PC 2.0; ya.ru) + 14 / 1 / 1 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3345; U; en) Presto/2.8.119 Version/11.10 + 13 / 1 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 + 13 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0 + 13 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET CLR 1.1.4322; InfoPath.2; .NET4.0E; MS-RTC LM 8) + 13 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 13 / 1 / 1 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.70 Safari/537.17 YE + 13 / 1 / 1 - Mozilla/5.0 (Linux; Android 4.1.1; HTC Desire X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 13 / 2 / 1 - Opera/9.80 (Android 2.3.6; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 13 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; Dealio Deskball 3.0) + 13 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 13 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; DefView) + 13 / 2 / 0 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 13 / 1 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1478.0 Safari/537.36 + 13 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30) + 12 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; BTRS129253; MRSPUTNIK 2, 4, 1, 105; MRA 8.0 (build 6017); SIMBAR={FB3C092F-6650-11E2-B314-00197D7E8F2A}; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Avant Browser) + 12 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3134; U; ru) Presto/2.8.119 Version/11.10 + 12 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11 + 12 / 1 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36 + 12 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22 + 12 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11 + 12 / 2 / 0 - Mozilla/5.0 (Windows NT 6.0; rv:13.0) Gecko/20100101 Firefox/13.0.1 + 12 / 0 / 0 - Mozilla/5.0 (compatible) Feedfetcher-Google;( http://www.google.com/feedfetcher.html) + 12 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 12 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) + 12 / 1 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:23.0) Gecko/20130405 Firefox/23.0 + 12 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 2.3.7; ru-ru; E15i Build/3.0.1.A.0.145; MiniCM7-2.2.1) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 12 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2) + 12 / 9 / 0 - Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0 + 12 / 1 / 0 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.5.22 Version/10.50 + 12 / 1 / 0 - Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1210091050) Presto/2.11.355 Version/12.10 + 12 / 1 / 1 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.8 (KHTML, like Gecko) Chrome/23.0.1250.0 Safari/537.8 + 12 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC_One_S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 11 / 1 / 1 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.73 Safari/537.36 + 11 / 1 / 1 - Mozilla/5.0 (Windows NT 5.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 11 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.1) Gecko/2008070208 + 11 / 1 / 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B145 + 11 / 1 / 0 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10A523 + 11 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 + 11 / 11 / 0 - Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) + 11 / 1 / 1 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1 + 11 / 1 / 1 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710) + 11 / 0 / 0 - facebookplatform/1.0 ( http://developers.facebook.com) + 11 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 11 / 1 / 0 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 + 11 / 0 / 0 - Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148 + 11 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.2; .NET CLR 1.1.4322; MS-RTC LM 8; .NET4.0E) + 11 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P5100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 11 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 + 10 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.15) Gecko/20101026 Firefox/3.5.15 + 10 / 4 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.10 Chromium/14.0.835.202 Chrome/14.0.835.202 Safari/535.1 + 10 / 2 / 0 - Mozilla/4.0 (compatible; MSIE 5.0; Windows 3.1; TUCOWS Network) + 10 / 8 / 0 - Kimengi/nineconnections.com + 10 / 0 / 0 - AppEngine-Google; ( http://code.google.com/appengine; appid: s~testpzgizmo) + 10 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) + 9 / 0 / 0 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10 + 9 / 5 / 0 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B329 Safari/8536.25 + 9 / 3 / 0 - Mozilla/5.0 (compatible; AhrefsBot/4.0; http://ahrefs.com/robot/) + 9 / 1 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; en-ru; IncredibleS_S710e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 9 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MS-RTC LM 8; AskTbFXTV5/5.15.15.35882; MSOffice 12) + 9 / 4 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0 + 9 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.47 Safari/537.36 + 9 / 1 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:10.0.6) Gecko/20100101 Firefox/10.0.6 Iceweasel/10.0.6 + 9 / 7 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/12.01 + 8 / 0 / 0 - Mozilla/4.0 (compatible;) + 8 / 1 / 0 - Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Qt/4.7.1 Safari/533.3 + 8 / 8 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9) Gecko/2008052906 Firefox/3.0 + 8 / 0 / 0 - Mozilla/5.0 (X11; Linux x86_64) KHTML/4.10.1 (like Gecko) Konqueror/4.10 + 8 / 0 / 0 - MobileSafari/8536.25 CFNetwork/609 Darwin/13.0.0 + 8 / 6 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; chromeframe/26.0.1410.64) + 7 / 0 / 0 - Microsoft-WebDAV-MiniRedir/6.2.9200 + 7 / 0 / 0 - Mozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm) SitemapProbe + 7 / 0 / 0 - Sogou web spider/4.0( http://www.sogou.com/docs/help/webmasters.htm#07) + 7 / 3 / 0 - Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:11.0) Gecko/20120313 Firefox/11.0 + 7 / 3 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/17.0 Firefox/17.0 + 7 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; Edition Next) Presto/2.12.388 Version/12.12 + 6 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 + 6 / 0 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20130512 Firefox/20.0 + 6 / 0 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17 + 6 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.14 (KHTML, like Gecko) Chrome/24.0.1292.0 Safari/537.14 + 6 / 0 / 0 - Mozilla/5.0 (compatible; Google Desktop/5.9.1005.12335; http://desktop.google.com/) + 6 / 6 / 0 - Opera/9.80 (Windows NT 6.1; Edition Yx) Presto/2.12.388 Version/12.10 + 6 / 5 / 0 - Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.10 + 6 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/6.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; AlexaToolbar/amzni-3.0; MALN; ms-office; MSOffice 14) + 6 / 3 / 0 - peerindex + 6 / 0 / 0 - Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101 + 6 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:6.0.1) Gecko/20100101 Firefox/6.0.1 + 5 / 0 / 0 - Mozilla/3.0 (OS/2; U) + 5 / 3 / 0 - msnbot-NewsBlogs/2.0b ( http://search.msn.com/msnbot.htm) + 5 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.229 Version/11.61 + 5 / 3 / 0 - Opera/9.80 (Android 2.3.5; Linux; Opera Mobi/ADR-1210241511) Presto/2.11.355 Version/12.10 + 5 / 1 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11 + 5 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4 u01-09 + 5 / 5 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11 + 5 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 + 5 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) + 5 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; InfoPath.2) + 5 / 2 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.289 Version/12.00 + 4 / 0 / 0 - Mozilla/5.0 (Linux; Android 4.1.1; A701 Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 4 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1518.0 Safari/537.36 + 4 / 2 / 0 - Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.10.289 Version/12.00 + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; MSOffice 12) + 4 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SLCC1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648) + 4 / 0 / 0 - MSFrontPage/12.0 + 4 / 0 / 0 - Mozilla/4.61 (Macintosh; I; PPC) + 4 / 0 / 0 - Mozilla/4.0 (compatible; MS FrontPage 12.0) + 4 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648) + 4 / 0 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.102 Safari/535.2 + 4 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) + 4 / 4 / 0 - DavClnt + 4 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 3.0.04506.648) + 4 / 0 / 0 - Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.69 Safari/537.17 + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E) + 4 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 3.0.04506.648) + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; PeoplePal 6.2) + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; 1A820D29-8445-92BE-2384-712BBCEDFDB1; MRSPUTNIK 2, 4, 1, 12; BTRS124447; GTB7.4; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727; AskTbFXTV5/5.8.0.12304; MSOffice 12) + 4 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3183; U; en) Presto/2.8.119 Version/11.10 + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6.6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 4 / 4 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1 + 4 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 AlexaToolbar/alxg-3.1 + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; AlexaToolbar/amzni-3.0; MALN; MSOffice 12) + 4 / 1 / 1 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; SLCC1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 3.0.04506.648) + 4 / 3 / 0 - Mozilla/5.0 (compatible; Exabot/3.0 (BiggerBetter); http://www.exabot.com/go/robot) + 4 / 1 / 1 - Mozilla/5.0 (Linux; U; Android 2.3.3; ru-ru; LG-P500 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2 + 4 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3271; U; en) Presto/2.8.119 Version/11.10 + 4 / 0 / 0 - Opera/9.80 (Windows NT 6.1; MRA 5.8 (build 4664)) Presto/2.12.388 Version/12.10 + 4 / 0 / 0 - MobileSafari/8536.25 CFNetwork/609.1.4 Darwin/13.0.0 + 4 / 0 / 0 - Sogou web spider/4.0 + 4 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.1; .NET4.0C) + 3 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.02 + 3 / 1 / 0 - Mozilla/5.0 (compatible; archive.org_bot http://www.archive.org/details/archive.org_bot) + 3 / 2 / 0 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.11 + 3 / 0 / 0 - Mozilla/5.0 (iPad; CPU OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3 + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C) + 3 / 0 / 0 - Googlebot-Video/1.0 + 3 / 1 / 0 - Xenu Link Sleuth/1.3.8 + 3 / 0 / 0 - Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 6089)) Presto/2.12.388 Version/12.15 + 3 / 0 / 0 - WordPress/3.5.1; http://peterpen-ctf.net + 3 / 2 / 0 - Lynx/2.8.8dev.15 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/2.12.20 + 3 / 3 / 0 - Java/1.6.0_26 + 3 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0 + 3 / 0 / 0 - Xenu Link Sleuth/1.3.9 beta + 3 / 0 / 0 - Opera/9.80 (Series 60; Opera Mini/7.0.29482/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 3 / 0 / 0 - WordPress/3.5.1; https://peterpen-ctf.net + 3 / 2 / 0 - Opera/9.80 (Windows NT 5.1; Edition Yx) Presto/2.12.388 Version/12.11 + 3 / 0 / 0 - URLGrabber + 3 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 2.2.1; ru-ru; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 3 / 0 / 0 - Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 5711)) Presto/2.12.388 Version/12.15 + 3 / 0 / 0 - Microsoft Office Word 2013 + 3 / 2 / 0 - Mozilla/5.0 (Windows NT 6.2; rv:16.0) Gecko/20100101 Firefox/16.0 + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser) + 3 / 0 / 0 - AndroidDownloadManager + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 3 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; A500 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 3 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0 + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) + 3 / 0 / 0 - GFGET/0.1 + 3 / 0 / 0 - Wget/1.10.1 + 3 / 0 / 0 - Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; Edition MacAppStore; ru) Presto/2.9.168 Version/11.52 + 3 / 0 / 0 - Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.15 + 3 / 2 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.12 (KHTML, like Gecko) Maxthon/3.0 Chrome/18.0.966.0 Safari/535.12 + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; MRSPUTNIK 2, 4, 0, 508; GTB7.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0) + 3 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; ms-office; MSOffice 14) + 3 / 0 / 0 - ia_archiver(OS-Wayback) + 2 / 1 / 0 - Links (2.7; Linux 3.8.0-19-generic i686; GNU C 4.7.1; text) + 2 / 2 / 0 - Mozilla/5.0 (compatible; YandexBot/3.0; MirrorDetector; http://yandex.com/bots) + 2 / 0 / 0 - Mozilla/5.0 (en-us) AppleWebKit/534.14 (KHTML, like Gecko; Google Wireless Transcoder) Chrome/9.0.597 Safari/534.14 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 95) Opera 7.03 [de] + 2 / 0 / 0 - Mozilla/5.0 (Android; Tablet; rv:17.0) Gecko/17.0 Firefox/17.0 + 2 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/6.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; AlexaToolbar/amzni-3.0; MALN) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Tablet PC 2.0) + 2 / 0 / 0 - Opera/9.80 (Windows NT 5.1; Edition Yx) Presto/2.12.388 Version/12.15 + 2 / 0 / 1 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1) + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + 2 / 0 / 0 - Mozilla/5.0 (Linux; Android 4.0.4; MT27i Build/6.1.1.B.1.54) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3134; U; en) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 + 2 / 2 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7 + 2 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 5.8 (build 4133)) Presto/2.12.388 Version/12.15 + 2 / 0 / 0 - User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 0 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:20.0) Gecko/20130507 Firefox/20.0 + 2 / 2 / 0 - Mozilla/5.0 (compatible; NetcraftSurveyAgent/1.0; info@netcraft.com) + 2 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1 + 2 / 1 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5976)) Presto/2.12.388 Version/12.11 + 2 / 1 / 0 - DoCoMo/2.0 P900i(c100;TB;W24H11) (compatible; ichiro/mobile goo; http://search.goo.ne.jp/option/use/sub4/sub4-1/) + 2 / 0 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:16.0) Gecko/20100101 Firefox/16.0 + 2 / 1 / 0 - Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.91 Safari/537.11 + 2 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0 + 2 / 1 / 0 - Opera/9.80 (Windows NT 6.1; MRA 6.0 (build 5976)) Presto/2.12.388 Version/12.10 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRA 5.5 (build 02842); InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 1 / 1 - Opera/9.80 (X11; Linux x86_64; Edition Next) Presto/2.12.388 Version/12.15 + 2 / 2 / 0 - Java/1.6.0_35 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0 05/02/2013 3:20:45 AM + 2 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; PAP4040_DUO Build/PrestigioPAP4040DUO) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 2 / 1 / 0 - Opera/9.80 (Windows NT 6.1; Win64; x64) Presto/2.12.388 Version/12.11 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET CLR 1.1.4322; InfoPath.3; .NET4.0E; MS-RTC LM 8; Microsoft Outlook 14.0.6025; ms-office; MSOffice 14) + 2 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.0.11) Firefox/1.5.0.11; 360Spider + 2 / 0 / 0 - Mozilla/5.0 (X11; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0 TinEye/1.0 (via http://www.tineye.com/) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Win64; x64; Trident/4.0; Avant Browser; .NET CLR 2.0.50727) + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3417; U; ru) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BTRS129253; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET4.0C; .NET4.0E; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 1 / 0 - Mozilla/5.0 + 2 / 1 / 0 - Mozilla/5.0 (Windows NT 6.0; rv:16.0) Gecko/20100101 Firefox/16.0 + 2 / 2 / 0 - Mozilla/4.0 (compatible; Netcraft Web Server Survey) + 2 / 0 / 0 - Opera/9.80 (Windows NT 5.1; Edition Yx) Presto/2.12.388 Version/12.14 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MANM) + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3638; U; ru) Presto/2.8.119 Version/11.10 + 2 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) YaBrowser/1.1.1084.5409 Chrome/19.1.1084.5409 Safari/536.5 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5 Nichrome/self/19 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 4, 1, 209; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C) + 2 / 0 / 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A525 Safari/8536.25 + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3134; U; ru) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/6.5.29194/29.3507; U; ru) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; eSobiSubscriber 1.0.0.40; BRI/2; MAAR; .NET4.0C) + 2 / 2 / 0 - Crowsnest/0.5 ( http://www.crowsnest.tv/) + 2 / 1 / 0 - Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.10 + 2 / 0 / 0 - Mozilla/5.0 (Linux; Android 4.1.2; GT-N8000 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Safari/537.36 + 2 / 1 / 0 - Mozilla/5.0 (X11; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0 + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3) + 2 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.289 Version/12.01 + 2 / 0 / 0 - Opera/9.80 (Windows NT 6.1; Edition Ukraine Local) Presto/2.12.388 Version/12.12 + 2 / 0 / 0 - Mozilla/5.0 (iPad; U; CPU OS 4_3_5 like Mac OS X; ru-ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5 + 2 / 1 / 0 - netEstate NE Crawler ( http://www.website-datenbank.de/) + 2 / 1 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 + 2 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.7; Google-SearchByImage) Gecko/2009021910 Firefox/3.0.7 + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3345; U; en) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1485.0 Safari/537.36 + 2 / 1 / 0 - Links (2.7; Linux 3.8.8 x86_64; GNU C 4.7.1; text) + 2 / 1 / 0 - SurcentroBot + 2 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MANMJS) + 2 / 2 / 0 - Mozilla/5.0 (compatible; Firefox Addon; Windows XP 5.1) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 4, 0, 516; GTB7.4; MRA 5.10 (build 5310); .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 2 / 0 / 0 - Mozilla/5.0 (Java; U; ru; nokiac5-00) AppleWebKit/530.13 (KHTML, like Gecko) UCBrowser/8.6.0.199/69/444/UCWEB Mobile UNTRUSTED/1.0 3gpp-gba + 2 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.0.29530/29.3709; U; ru) Presto/2.8.119 Version/11.10 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:2.0b7pre) Gecko/20100921 Firefox/4.0b7pre + 2 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; MASMJS) + 2 / 2 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 + 2 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; NP06) + 2 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; InfoPath.3) + 2 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 + 2 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; GTB6.6; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.30618; OfficeLiveConnector.1.5; OfficeLivePatch.1.3; .NET4.0C) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30 Nichrome/self/12 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:20.0) Gecko/20100101 Firefox/20.0 IceDragon/20.0.1.14 + 1 / 0 / 0 - Opera/9.80 (Android; Opera Mini/7.0.29952/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.96 Safari/537.4 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.13 + 1 / 1 / 0 - SEO Browser + 1 / 0 / 0 - CodeGator Crawler v1.0 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0) Gecko/20100101 Firefox/7.0 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; InfoPath.1) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TencentTraveler) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; MRA 6.0 (build 6068)) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 5972)) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Opera/9.80 (X11; Linux zbov) Presto/2.11.355 Version/12.10 + 1 / 1 / 0 - Microsoft Office Mobile /14.0 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/17.0 Firefox/17.0 + 1 / 1 / 0 - Opera/9.80 (Windows NT 5.1; U; YB/3.5.1; ru) Presto/2.10.229 Version/11.64 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 + 1 / 0 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 1 / 0 / 0 - Opera/9.80 (J2ME/MIDP; Opera Mini/7.1.32052/29.3417; U; ru) Presto/2.8.119 Version/11.10 + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; BOIE9;ENUS) + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.2; WOW64) Presto/2.12.388 Version/12.11 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; U; MRA 5.8 (build 4664); ru) Presto/2.10.229 Version/11.60 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0 + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.1; MRA 6.0 (build 5970)) Presto/2.12.388 Version/12.11 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5704)) Presto/2.12.388 Version/12.11 + 1 / 1 / 0 - Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.1) Gecko/20090630 Fedora/3.5-1.fc11 Firefox/3.5 GTB5 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 999.1; Unknown) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/6.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; AlexaToolbar/amzni-3.0; MALN; ms-office) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TencentTraveler ; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; MRA 8.0 (build 6008)) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TencentTraveler ; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727 ; .NET CLR 4.0.30319) + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; MRA 5.7 (build 03789)) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; Touch; MASMJS) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Nevz Group Policy option; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; Nevz Group Policy option) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; Edition Yx) Presto/2.12.388 Version/12.10 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MS-RTC LM 8; ms-office; MSOffice 14) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; Edition Next; Edition Yx; ru) Presto/2.11.310 Version/12.50 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20121026 Firefox/16.0 SeaMonkey/2.13.2 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0 TinEye/1.0 (via http://www.tineye.com/) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E3AFBC29-379F-6981-3477-F67AEAD253D3}; .NET CLR 1.1.4322; .NET CLR 2.0.50727; OfficeLiveConnector.1.3; OfficeLivePatch.0.0) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; DepositFiles/FileManager 0.9.9.206 YB/5.0.3) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 2, 0, 86; MRIE8PACK 2.0.1) + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.229 Version/11.60 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.9.168 Version/11.51 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; MRA 6.0 (build 5972)) Presto/2.12.388 Version/12.10 + 1 / 0 / 0 - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11 + 1 / 1 / 0 - Jakarta Commons-HttpClient/3.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; .NET4.0C; .NET4.0E) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 3.5.30729) + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.2; WOW64; MRA 8.0 (build 5784)) Presto/2.12.388 Version/12.11 + 1 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.9 (build 01863); MRSPUTNIK 2, 4, 1, 162) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 1 / 0 / 0 - Opera/9.80 (X11; Linux i686; U; ru) Presto/2.7.62 Version/11.01 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET CLR 1.1.4322; InfoPath.3; .NET4.0E; ms-office; MSOffice 14) + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.9.168 Version/11.50 + 1 / 0 / 0 - Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; ru-ru) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Safari/530.17 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Maxthon/3.0 Chrome/22.0.1229.79 Safari/537.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.5 (KHTML, like Gecko) YaBrowser/1.1.1084.5409 Chrome/19.1.1084.5409 Safari/536.5 + 1 / 1 / 0 - Opera/9.80 (Windows NT 5.1; U; Edition Yx; ru) Presto/2.10.289 Version/12.02 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1.0 Safari/537.11 + 1 / 1 / 0 - MFE_expand/0.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.1) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0) Gecko/20100101 Firefox/9.0 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11 + 1 / 0 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 + 1 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 + 1 / 0 / 0 - Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; ru-ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 5998)) Presto/2.12.388 Version/12.11 + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MASEJS) + 1 / 0 / 0 - Linguee Bot (http://www.linguee.com/bot; bot@linguee.com) + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.289 Version/12.00 + 1 / 0 / 0 - Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; MRA 5.9 (build 4953); ru) Presto/2.10.229 Version/11.60 + 1 / 0 / 0 - HttpComponents/1.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0 05/02/2013 3:20:44 AM + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/6.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; ms-office) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 + 1 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9100 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13 BuiltWith/1.2 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 5.2; rv:12.0) Gecko/20100101 Firefox/12.0 + 1 / 1 / 0 - Opera/9.80 (Windows NT 5.1; U; MRA 8.0 (build 5784); ru) Presto/2.10.289 Version/12.02 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10 + 1 / 1 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.82 Safari/537.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2; rv:14.0) Gecko/20100101 Firefox/14.0.1 + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; KB974488) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 5.10 (build 5218); MRSPUTNIK 2, 4, 0, 501; InfoPath.2) + 1 / 0 / 0 - QuerySeekerSpider ( http://queryseeker.com/bot.html ) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2) + 1 / 1 / 0 - PageAnalyzer/1.3b (www.the-escape.co.uk) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.4; MRA 6.0 (build 6005); User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1); .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1; .NET4.0C; .NET4.0E; MRIE8PACK 2.0.1) + 1 / 1 / 0 - CheckSite Verification Agent ( http://www.checksite.us) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Iron/25.0.1400.0 Chrome/25.0.1400.0 Safari/537.22 + 1 / 1 / 0 - EventMachine HttpClient + 1 / 0 / 0 - Mozilla/5.0 (Android; Mobile; rv:20.0.1) Gecko/20.0.1 Firefox/20.0.1 + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.1; U; YB/3.5.1; ru) Presto/2.6.30 Version/10.63 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 8.0 (build 5988)) Presto/2.12.388 Version/12.15 + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.1; U; Edition Next; ru) Presto/2.11.310 Version/12.50 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; U; Edition Yx; ru) Presto/2.10.289 Version/12.02 + 1 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 2.2; fr-fr; Desire_A8181 Build/FRF91) App3leWebKit/53.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDR; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322; Tablet PC 2.0) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22,gzip(gfe) (via docs.google.com/viewer) + 1 / 1 / 0 - Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.10 + 1 / 1 / 0 - Apache-HttpClient/4.2.3 (java 1.5) + 1 / 1 / 0 - Mozilla/5.0 (compatible; NetSeer crawler/2.0; http://www.netseer.com/crawler.html; crawler@netseer.com) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 (C67D51D4-DE8A-25CA-C613-17B73EBB7584) Firefox/7.0.1 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 + 1 / 0 / 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22 CoolNovo/2.0.7.11 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20100101 Firefox/20.0 SeaMonkey/2.17.1 + 1 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1469.0 Safari/537.36 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.65 Safari/537.36 + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0; BOIE9;RURU) + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20 + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; MRA 8.0 (build 5880); ru) Presto/2.10.289 Version/12.02 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.25) Gecko/20111212 Firefox/3.6.25 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.02 Bork-edition [en] + 1 / 1 / 0 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Contact: feedback@getprismatic.com + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C) + 1 / 0 / 0 - Opera/9.80 (Android 4.0.3; Linux; Opera Tablet/ADR-1301080958) Presto/2.11.355 Version/12.10 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 4, 1, 105; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; AskTbPTV/5.15.1.22229; .NET4.0C) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.2; MRSPUTNIK 2, 4, 1, 105; InfoPath.1) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.1634 Safari/535.19 YI + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) YaBrowser/1.1.1084.5409 Chrome/19.1.1084.5409 Safari/536.5 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 6048)) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.2; WOW64; Edition Yx) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.10 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; Edition Next; ru) Presto/2.9.220 Version/12.00 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; MRA 6.0 (build 5680); ru) Presto/2.10.289 Version/12.00 + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0,gzip(gfe) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 6015)) Presto/2.12.388 Version/12.15 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 5.8 (build 4157); .NET CLR 2.0.50727; AskTbPTV/5.11.3.15590) + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3 (.NET CLR 3.5.30729) + 1 / 0 / 0 - NSPlayer/12.00.7601.17514 WMFSDK/12.00.7601.17514 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; U; MRA 5.9 (build 4953); ru) Presto/2.10.229 Version/11.60 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 5.10 (build 5310)) Presto/2.12.388 Version/12.10 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; Edition Yx; ru) Presto/2.10.229 Version/11.62 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDR; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322; Tablet PC 2.0); 360Spider + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 AlexaToolbar/alxg-3.1 + 1 / 1 / 0 - Microsoft Office Mobile/15.0 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.2; rv:20.0) Gecko/20100101 Firefox/20.0 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.22 Version/10.51 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0E) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; MRSPUTNIK 2, 4, 0, 516; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0) + 1 / 0 / 0 - Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-I9100 Build/JZO54K) + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0; EIE10;RURUWOL) + 1 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 + 1 / 0 / 0 - (null) + 1 / 0 / 0 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322) + 1 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; MS-RTC LM 8; BRI/2; .NET4.0E) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.0; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 + 1 / 0 / 0 - Opera/9.80 (Series 60; Opera Mini/7.1.32449/29.3530; U; ru) Presto/2.8.119 Version/11.10 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.2.2.0 Safari/537.31 + 1 / 0 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1105.412 YaBrowser/1.5.1105.412 Safari/537.4 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1300.0 Iron/23.0.1300.0 Safari/537.11 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.10.289 Version/12.02 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E; MSOffice 12) + 1 / 0 / 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P3100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 1 / 0 / 0 - Opera/9.80 (Windows NT 5.1; U; en) Presto/2.10.289 Version/12.01 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.91 Safari/537.11 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; MRA 6.0 (build 6001); ru) Presto/2.10.289 Version/12.01 + 1 / 0 / 0 - Opera/9.64 (Windows NT 5.1; U; ru) Presto/2.1.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.0; U; ru) Presto/2.9.168 Version/11.50 + 1 / 1 / 0 - Opera/9.80 (Windows NT 6.1; Win64; x64) Presto/2.12.388 Version/12.10 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.229 Version/11.62 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7 YE + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.3; .NET CLR 2.0.50727) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; ru; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 11.60 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; MRA 5.8 (build 4157)) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 5.1; en-US) AppleWebKit/535.12 (KHTML, like Gecko) Version/5.0.1 Safari/535.12 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRSPUTNIK 2, 4, 0, 501; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 3.5.30729; .NET CLR 3.0.30729) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 5976)) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E; MSOffice 12) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; Win64; x64; Edition Yx) Presto/2.12.388 Version/12.11 + 1 / 0 / 0 - rarely used + 1 / 1 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 + 1 / 1 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C) + 1 / 0 / 0 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; MRSPUTNIK 2, 4, 1, 105; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Tablet PC 2.0) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31 AlexaToolbar/pDvbmwUg-1.3 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; NP06) + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0) Gecko/20100101 Firefox/10.0 + 1 / 0 / 0 - Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20100101 Firefox/20.0 + 1 / 0 / 0 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Tablet PC 2.0; MSOffice 12) + 1 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0 + 1 / 0 / 0 - Opera/9.80 (Android 4.0.3; Linux; Opera Mobi/ADY-1305080823) Presto/2.11.355 Version/12.10 + 1 / 0 / 0 - Opera/9.80 (J2ME/MIDP; Opera Mini/4.3.13057/29.3530; U; ru) Presto/2.8.119 Version/11.10 + 1 / 1 / 0 - Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 YB/3.5.1 (.NET CLR 3.5.30729) + 1 / 0 / 0 - Opera/9.80 (Windows NT 6.1; WOW64; MRA 6.0 (build 6042)) Presto/2.12.388 Version/12.15 + + botreq / bothits (26916 / 12055) - user_agent (40) +5448 / 0 - msnbot-media/1.1 ( http://search.msn.com/msnbot.htm) +4162 / 2557 - Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html) +3202 / 0 - Mozilla/5.0 (compatible; YandexImages/3.0; http://yandex.com/bots) +3038 / 2351 - Mozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm) +2650 / 2044 - Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7 (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) +1937 / 1676 - Mozilla/5.0 (compatible; YandexBot/3.0; http://yandex.com/bots) +1900 / 0 - Googlebot-Image/1.0 +1543 / 1408 - Mozilla/5.0 (compatible; SearchBot) + 519 / 280 - SolomonoBot/1.04 (http://www.solomono.ru) + 400 / 387 - Mozilla/5.0 (compatible; Linux i686; Yandex.Gazeta Bot/1.0; http://gazeta.yandex.ru) + 303 / 293 - Mozilla/5.0 (compatible; Linux x86_64; Mail.RU_Bot/2.0; http://go.mail.ru/help/robots) + 250 / 218 - msnbot/2.0b ( http://search.msn.com/msnbot.htm) + 244 / 0 - Googlebot/2.1 ( http://www.google.com/bot.html) + 185 / 154 - SAMSUNG-SGH-E250/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Browser/6.2.3.3.c.1.101 (GUI) MMP/2.0 (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) + 183 / 61 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.changedetection.com/bot.html ) + 175 / 148 - DoCoMo/2.0 N905i(c100;TB;W24H16) (compatible; Googlebot-Mobile/2.1; http://www.google.com/bot.html) + 132 / 113 - Mozilla/5.0 (compatible; Mail.RU_Bot/2.0; http://go.mail.ru/help/robots) + 121 / 58 - Mozilla/5.0 (compatible; Ezooms/1.0; ezooms.bot@gmail.com) + 75 / 56 - Mozilla/5.0 (compatible; MJ12bot/v1.4.3; http://www.majestic12.co.uk/bot.php? ) + 72 / 40 - Mozilla/5.0 (compatible; YandexDirect/3.0; http://yandex.com/bots) + 51 / 41 - Mozilla/5.0 (compatible; TweetedTimes Bot/1.0; http://tweetedtimes.com) + 47 / 39 - Wotbox/2.01 ( http://www.wotbox.com/bot/) + 40 / 0 - Mozilla/5.0 (compatible; YandexImageResizer/2.0; http://yandex.com/bots) + 40 / 19 - rogerbot/1.0 (http://www.seomoz.org/dp/rogerbot, rogerbot-crawler shiny@seomoz.org) + 39 / 19 - Twitterbot/1.0 + 32 / 27 - Mozilla/5.0 (compatible; TweetmemeBot/3.0; http://tweetmeme.com/) + 28 / 24 - Mozilla/5.0 (compatible; PaperLiBot/2.1; http://support.paper.li/entries/20023257-what-is-paper-li) + 26 / 20 - Mozilla/5.0 (compatible; ZumBot/1.0; http://help.zum.com/inquiry) + 19 / 0 - Mozilla/5.0 (compatible; special_archiver/3.1.1 http://www.archive.org/details/archive.org_bot) + 18 / 9 - Mozilla/5.0 (compatible; YandexFavicons/1.0; http://yandex.com/bots) + 9 / 3 - Mozilla/5.0 (compatible; AhrefsBot/4.0; http://ahrefs.com/robot/) + 7 / 0 - Mozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm) SitemapProbe + 5 / 3 - msnbot-NewsBlogs/2.0b ( http://search.msn.com/msnbot.htm) + 4 / 3 - Mozilla/5.0 (compatible; Exabot/3.0 (BiggerBetter); http://www.exabot.com/go/robot) + 3 / 0 - Googlebot-Video/1.0 + 3 / 1 - Mozilla/5.0 (compatible; archive.org_bot http://www.archive.org/details/archive.org_bot) + 2 / 1 - SurcentroBot + 2 / 2 - Mozilla/5.0 (compatible; YandexBot/3.0; MirrorDetector; http://yandex.com/bots) + 1 / 0 - Linguee Bot (http://www.linguee.com/bot; bot@linguee.com) + 1 / 0 - QuerySeekerSpider ( http://queryseeker.com/bot.html ) + + mobihits (1107) - user_agent (156) +181 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 +176 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 + 76 - Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3 + 60 - Mozilla/5.0 (Linux; U; Android 2.2; ru-ru; HTC_Gratia_A6380 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 30 - Mozilla/5.0 (Linux; Android 4.0.4; HTC Incredible S Build/IMM76D) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 26 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25 + 25 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mozart T8698) + 24 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25 + 24 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25 + 21 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 19 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9300 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 18 - Opera/9.80 (Android 4.0.4; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 17 - Opera/9.80 (Android 4.0.3; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 17 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A8426 Safari/8536.25 + 17 - Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1212030820) Presto/2.11.355 Version/12.10 + 16 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9100 Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 15 - Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 13 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 13 - Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/ADR-1301080958) Presto/2.11.355 Version/12.10 + 12 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800) + 11 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 11 - Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; HTC Sensation Z710e Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 11 - Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B206 + 11 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 10 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/25.0.1364.124 Mobile/10B329 Safari/8536.25 + 9 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; SonyEricssonLT26w Build/6.1.A.2.55) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 9 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 9 - Mozilla/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25 + 8 - Mozilla/5.0 (Linux; U; Android 3.2; ru-ru; GT-P7300 Build/HTJ85B) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 + 8 - Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920) + 7 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; EVO3D_X515m Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 7 - Mozilla/5.0 (Linux; Android 4.0.4; ZTE Grand Era Build/IMM76L) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.40 Mobile Safari/537.31 OPR/14.0.1074.54070 + 6 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 5 - Mozilla/5.0 (Linux; U; Android 2.2.1; ru-ru; HTC Wildfire Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 5 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; HTC_DesireS_S510e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 5 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B145 [FBAN/FBIOS;FBAV/6.0.2;FBBV/183159;FBDV/iPhone4,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/6.1.1;FBSS/2; FBCR/O2;FBID/phone;FBLC/en_US;FBOP/1] + 5 - Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; LG-E510 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.53 Mobile/10B329 Safari/8536.25 + 5 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25 + 5 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B329 Safari/8536.25 + 5 - Mozilla/5.0 (Linux; Android 4.0.4; U8836D Build/HuaweiU8836D) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 5 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9100 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 4 - Opera/9.80 (Android; Opera Mini/7.0.29733/29.3271; U; en) Presto/2.8.119 Version/11.10 + 4 - Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B176 + 4 - Mozilla/5.0 (Linux; Android 4.0.4; ST26i Build/11.0.A.3.18) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 4 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Safari/537.22 + 4 - Opera/9.80 (Android; Opera Mini/7.5.33286/29.3345; U; en) Presto/2.8.119 Version/11.10 + 4 - Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 4 - Mozilla/5.0 (Linux; Android 4.1.2; ST26i Build/11.2.A.0.21) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 4 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; SP-A20i Build/MF_ICS_02.19) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 3 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B146 Safari/8536.25 + 3 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 3 - Opera/9.80 (Android; Opera Mini/6.5.27452/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 3 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3417; U; ru) Presto/2.8.119 Version/11.10 + 3 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B146 + 3 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 3 - Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0 + 3 - Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3 + 3 - Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B208 Safari/7534.48.3 + 3 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; SonyST26i Build/11.2.A.0.21) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 3 - Mozilla/5.0 (Android; Tablet; rv:21.0) Gecko/21.0 Firefox/21.0 + 3 - Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 3 - Mozilla/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B141 Safari/8536.25 + 3 - Opera/9.80 (Android 2.3.5; Linux; Opera Mobi/ADR-1210241511) Presto/2.11.355 Version/12.10 + 2 - Mozilla/5.0 (Linux; Android 4.0.3; U9200 Build/HuaweiU9200) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 2 - Mozilla/5.0 (iPod; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B329 + 2 - Mozilla/5.0 (Linux; Android 4.2.2; Galaxy Nexus Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.54 Mobile Safari/537.31 + 2 - Opera/9.80 (Android; Opera Mini/6.5.29194/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 2 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3594; U; ru) Presto/2.8.119 Version/11.10 + 2 - Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireHD_A9191 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 2 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 2 - Mozilla/5.0 (Linux; Android 4.0.4; ZTE Grand Era Build/IMM76L) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 2 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I9300 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 2 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 920) + 2 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; Liquid MT Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 2 - Mozilla/5.0 (Android; Tablet; rv:20.0) Gecko/20.0 Firefox/20.0 + 2 - Opera/9.80 (Android 4.1.2; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 2 - Mozilla/5.0 (Linux; Android 4.0.3; HUAWEI MediaPad Build/HuaweiMediaPad) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 2 - Mozilla/5.0 (Linux; U; Android 2.3.5; en-ru; HTC_DesireS_S510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 2 - Opera/9.80 (Android 2.3.6; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 2 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B143 Safari/8536.25 + 1 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710) + 1 - Mozilla/5.0 (Linux; Android 4.1.2; SAMSUNG-SGH-I727 Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 1 - Mozilla/5.0 (Linux; Android 4.0.4; ST25i Build/6.1.1.B.1.10) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 1 - Mozilla/5.0 (iPad; CPU OS 6_1_2 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/26.0.1410.50 Mobile/10B146 Safari/8536.25 + 1 - Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350) + 1 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P5100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 1 - Mozilla/5.0 (Android; Mobile; rv:20.0) Gecko/20.0 Firefox/20.0 + 1 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC Sensation Z710e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 - Mozilla/5.0 (Linux; U; Android 4.0.4; en-ru; IncredibleS_S710e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9070 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 1 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S5830i Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 1 - Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireS_S510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 1 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10A523 + 1 - Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 1 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; IncredibleS_S710e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 - Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/ADR-1301071820) Presto/2.11.355 Version/12.10 + 1 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3530; U; en) Presto/2.8.119 Version/11.10 + 1 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; NEWMAN N1 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 1 - Mozilla/5.0 (Linux; U; Android 2.3.3; ru-ru; LG-P500 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2 + 1 - Mozilla/5.0 (Linux; U; Android 2.3.7; ru-ru; E15i Build/3.0.1.A.0.145; MiniCM7-2.2.1) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 1 - Mozilla/5.0 (Linux; Android 4.1.1; GT-N8000 Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 + 1 - Microsoft Office Mobile/15.0 + 1 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3183; U; ru) Presto/2.8.119 Version/11.10 + 1 - Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1210091050) Presto/2.11.355 Version/12.10 + 1 - Opera/9.80 (Android; Opera Mini/7.5.33361/29.3345; U; en) Presto/2.8.119 Version/11.10 + 1 - Microsoft Office Mobile /14.0 + 1 - Mozilla/5.0 (Linux; Android 4.1.1; HTC Desire X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 1 - Mozilla/5.0 (Linux; Android 4.1.2; GT-I8190 Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 + 1 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B145 + 1 - Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 1 - DoCoMo/2.0 P900i(c100;TB;W24H11) (compatible; ichiro/mobile goo; http://search.goo.ne.jp/option/use/sub4/sub4-1/) + 0 - Mozilla/5.0 (iPad; CPU OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3183; U; en) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; A500 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 0 - Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; ru-ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 + 0 - Mozilla/5.0 (iPad; U; CPU OS 4_3_5 like Mac OS X; ru-ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5 + 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A525 Safari/8536.25 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3271; U; en) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3134; U; ru) Presto/2.8.119 Version/11.10 + 0 - Opera/9.80 (Android 4.0.3; Linux; Opera Tablet/ADR-1301080958) Presto/2.11.355 Version/12.10 + 0 - Opera/9.80 (Android; Opera Mini/6.5.29194/29.3507; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; Android 4.1.1; A701 Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 + 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P3100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 + 0 - Opera/9.80 (Android; Opera Mini/7.5.33286/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3345; U; en) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; Android 4.0.4; MT27i Build/6.1.1.B.1.54) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3134; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-I8150 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 0 - Opera/9.80 (Android; Opera Mini/7.0.29530/29.3709; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; GT-I9100 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 0 - Mozilla/5.0 (Java; U; ru; nokiac5-00) AppleWebKit/530.13 (KHTML, like Gecko) UCBrowser/8.6.0.199/69/444/UCWEB Mobile UNTRUSTED/1.0 3gpp-gba + 0 - Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-I9001 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3417; U; ru) Presto/2.8.119 Version/11.10 + 0 - Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-I9100 Build/JZO54K) + 0 - Mozilla/5.0 (Linux; Android 4.1.2; GT-N8000 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Safari/537.36 + 0 - Mozilla/5.0 (Linux; U; Android 2.2.1; ru-ru; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 0 - MobileSafari/8536.25 CFNetwork/609 Darwin/13.0.0 + 0 - Mozilla/5.0 (Android; Tablet; rv:17.0) Gecko/17.0 Firefox/17.0 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32200/29.3134; U; en) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Android; Mobile; rv:20.0.1) Gecko/20.0.1 Firefox/20.0.1 + 0 - Opera/9.80 (Android 4.0.3; Linux; Opera Mobi/ADY-1305080823) Presto/2.11.355 Version/12.10 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32195/29.3638; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25 + 0 - Opera/9.80 (Android; Opera Mini/7.0.29952/29.3271; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X; ru-ru) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.82 Mobile/10A523 Safari/7534.48.3 + 0 - Opera/9.80 (Android; Opera Mini/7.5.32193/29.3345; U; ru) Presto/2.8.119 Version/11.10 + 0 - Mozilla/5.0 (Linux; Android 4.2.1; Galaxy Nexus Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 + 0 - Mozilla/5.0 (Linux; U; Android 2.2; fr-fr; Desire_A8181 Build/FRF91) App3leWebKit/53.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 + 0 - MobileSafari/8536.25 CFNetwork/609.1.4 Darwin/13.0.0 + 0 - Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC_One_S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 + 0 - AndroidDownloadManager + 0 - Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; PAP4040_DUO Build/PrestigioPAP4040DUO) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/UserAgentTest.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/UserAgentTest.php new file mode 100644 index 0000000000..e7bcc65475 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/UserAgentTest.php @@ -0,0 +1,192 @@ +detect = new Mobile_Detect; + } + + public static function generateJson() + { + //in case this gets run multiple times + if (isset(self::$json)) { + return self::$json; + } + + //the json and PHP formatted files + $jsonFile = dirname(__FILE__) . '/ualist.json'; + $phpFile = dirname(__FILE__) . '/UA_List.inc.php'; + + //currently stored as a PHP array + $list = include $phpFile; + + //check recency of the file + if (file_exists($jsonFile) && is_readable($jsonFile)) { + //read the json file + $json = json_decode(file_get_contents($jsonFile), true); + + //check that the hash matches + $hash = isset($json['hash']) ? $json['hash'] : null; + + if ($hash == sha1(serialize($list))) { + //file is up to date, just read the json file + self::$json = $json['user_agents']; + + return self::$json; + } + } + + + //uses the UA_List.inc.php to generate a json file + if (file_exists($jsonFile) && !is_writable($jsonFile)) { + throw new RuntimeException("Need to be able to create/update $jsonFile from UA_List.inc.php."); + } + + if (!is_writable(dirname($jsonFile))) { + throw new RuntimeException("Insufficient permissions to create this file: $jsonFile"); + } + + + + //print_r($list['Acer']); exit; + + $json = array(); + + foreach ($list as $vendor => $vendorList) { + foreach ($vendorList as $userAgent => $props) { + if (is_int($userAgent)) { + //this means that the user agent is the props + $userAgent = $props; + $props = array(); + } + + $tmp = array( + 'vendor' => $vendor, + 'user_agent' => $userAgent + ); + + if (isset($props['isMobile'])) { + $tmp['mobile'] = $props['isMobile']; + } + + if (isset($props['isTablet'])) { + $tmp['tablet'] = $props['isTablet']; + } + + if (isset($props['version'])) { + $tmp['version'] = $props['version']; + } + + if (isset($props['model'])) { + $tmp['model'] = $props['model']; + } + + $json[] = $tmp; + } + } + + //save the hash + $hash = sha1(serialize($list)); + $json = array( + 'hash' => $hash, + 'user_agents' => $json + ); + + if (defined('JSON_PRETTY_PRINT')) { + $jsonString = json_encode($json, JSON_PRETTY_PRINT); + } else { + $jsonString = json_encode($json); + } + + file_put_contents($jsonFile, $jsonString); + self::$json = $json['user_agents']; + + return self::$json; + } + + public static function setUpBeforeClass() + { + //generate json file first + self::generateJson(); + + //get the generated JSON data + $json = self::$json; + + //make a list that is usable by functions (THE ORDER OF THE KEYS MATTERS!) + foreach ($json as $userAgent) { + $tmp = array(); + $tmp[] = isset($userAgent['user_agent']) ? $userAgent['user_agent'] : null; + $tmp[] = isset($userAgent['mobile']) ? $userAgent['mobile'] : null; + $tmp[] = isset($userAgent['tablet']) ? $userAgent['tablet'] : null; + $tmp[] = isset($userAgent['version']) ? $userAgent['version'] : null; + $tmp[] = isset($userAgent['model']) ? $userAgent['model'] : null; + $tmp[] = isset($userAgent['vendor']) ? $userAgent['vendor'] : null; + + self::$ualist[] = $tmp; + } + } + + public function userAgentData() + { + if (!count(self::$ualist)) { + self::setUpBeforeClass(); + } + + return self::$ualist; + } + + /** + * @medium + * @dataProvider userAgentData + */ + public function testUserAgents($userAgent, $isMobile, $isTablet, $version, $model, $vendor) + { + //make sure we're passed valid data + if (!is_string($userAgent) || !is_bool($isMobile) || !is_bool($isTablet)) { + $this->markTestIncomplete("The User-Agent $userAgent does not have sufficient information for testing."); + + return; + } + + //setup + $this->detect->setUserAgent($userAgent); + + //is mobile? + $this->assertEquals($isMobile, $this->detect->isMobile()); + + //is tablet? + $this->assertEquals($isTablet, $this->detect->isTablet(), 'FAILED: ' . $userAgent . ' isTablet: ' . $isTablet); + + if (isset($version)) { + foreach ($version as $condition => $assertion) { + $this->assertEquals($assertion, $this->detect->version($condition), 'FAILED UA (version("'.$condition.'")): '.$userAgent); + } + } + + //version property tests + if (isset($version)) { + foreach ($version as $property => $stringVersion) { + $v = $this->detect->version($property); + $this->assertSame($stringVersion, $v); + } + } + + //@todo: model test, not sure how exactly yet + //@todo: vendor test. The below is theoretical, but fails 50% of the tests... + /*if (isset($vendor)) { + $method = "is$vendor"; + $this->assertTrue($this->detect->{$method}(), "Expected Mobile_Detect::{$method}() to be true."); + }*/ + } +} diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/VendorsTest_tmp.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/VendorsTest_tmp.php new file mode 100644 index 0000000000..6190ebdb22 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/VendorsTest_tmp.php @@ -0,0 +1,91 @@ +detect = new Mobile_Detect; + + } + + public static function setUpBeforeClass() + { + //this method could be called multiple times + if (!self::$items) { + self::$items = include dirname(__FILE__).'/UA_List.inc.php'; + } + } + + public function testisMobileIsTablet() + { + foreach (self::$items as $brand => $deviceArr) { + foreach ($deviceArr as $userAgent => $conditions) { + if (!is_array($conditions)) { + continue; + } + + $this->detect->setUserAgent($userAgent); + + foreach ($conditions as $condition => $assert) { + // Currently not supporting version and model here. + // @todo: I need to split this tests! + if (in_array($condition, array('model'))) { + continue; + } // 'version', + + switch ($condition) { + case 'version': + // Android, iOS, Chrome, Build, etc. + foreach ($assert as $assertKey => $assertValue) { + //if ($brand == 'Apple') { + // echo 'UA ('.$condition.'('.$assertKey.') === '.$assertValue.'): '.$userAgent . "\n"; + //} + $this->assertSame( $this->detect->$condition( $assertKey ), $assertValue, 'UA ('.$condition.'('.$assertKey.') === '.$assertValue.'): '.$userAgent); + } + break; + + default: + $this->assertSame($this->detect->$condition(), $assert, 'UA ('.$condition.'): '.$userAgent); + break; + } + + } + + } + + } + + } + + public function testVersion() + { + foreach (self::$items as $brand => $deviceArr) { + + foreach ($deviceArr as $userAgent => $conditions) { + + if ( !is_array($conditions) || !isset($conditions['version']) ) { continue; } + + $this->detect->setUserAgent($userAgent); + + foreach ($conditions['version'] as $condition => $assertion) { + + $this->assertEquals( $this->detect->version($condition), $assertion, 'UA (version("'.$condition.'")): '.$userAgent ); + + } + + } + + } + + } + +} diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/bootstrap.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/bootstrap.php new file mode 100644 index 0000000000..6cd37f7bf1 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/bootstrap.php @@ -0,0 +1,2 @@ + + + + + + + + + + ./ + + + + + ../Mobile_Detect.php + + + diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/AOC.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/AOC.php new file mode 100644 index 0000000000..8f5a096168 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/AOC.php @@ -0,0 +1,7 @@ + array( + 'Mozilla/5.0 (Linux; Android 4.0.4; MW0922 Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-us; MW0831Plus Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ) +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Acer.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Acer.php new file mode 100644 index 0000000000..0eef47d1f3 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Acer.php @@ -0,0 +1,29 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 3.2.1; en-us; A100 Build/HTK55D) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; A110 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; A200 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Webkit' => '534.30', 'Safari' => '4.0', 'Build' => 'IML74K'), 'model' => 'A200' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; A500 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; A501 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; A701 Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; B1-A71 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; B1-710 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; A1-810 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; nl-nl; A1-810 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Acer; Allegro)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; A3-A10 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, 'version' => array( + 'Android' => '4.2.2', 'Build' => 'JDQ39', 'Webkit' => '537.36', 'Chrome' => '32.0.1700.99', + ), + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; A1-811 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; A1-830 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; A3-A11 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; A3-A40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36' => array('isMobile' => true, 'isTablet' => true) + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Alcatel.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Alcatel.php new file mode 100644 index 0000000000..96a36ac35e --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Alcatel.php @@ -0,0 +1,49 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-in; MB525 Build/GWK74; CyanogenMod-7.2.0) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; it-it; ALCATEL ONE TOUCH 918D Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '2.3.5', 'Webkit' => '533.1', 'Safari' => '4.0', 'Build' => 'GRJ90'), 'model' => 'ONE TOUCH 918D' ), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; ALCATEL ONE TOUCH 991 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '2.3.6', 'Webkit' => '533.1', 'Safari' => '4.0', 'Build' => 'GRJ90'), 'model' => 'ONE TOUCH 991' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; ALCATEL ONE TOUCH 993D Build/ICECREAM) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.0.4', 'Webkit' => '534.30', 'Safari' => '4.0', 'Build' => 'ICECREAM'), 'model' => 'ONE TOUCH 993D' ), + 'ALCATEL_A392G/1.0 ObigoInternetBrowser/Q05A[TF013513002719521000000013182904148]' => array('isMobile' => true, 'isTablet' => false, 'model' => 'A392G'), + 'ALCATEL_3020D/1.0 ObigoInternetBrowser/Q03C' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2; ALCATEL ONE TOUCH 5037A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'ALCATEL_3020G/1.0 ObigoInternetBrowser/Q03C' => array('isMobile' => true, 'isTablet' => false), + 'ALCATEL_3041D/1.0 ObigoInternetBrowser/Q03C' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 5037E Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 5037X Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 5037X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012A Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-nz; ONE TOUCH 6012A Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012D Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; ONE TOUCH 6012D Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; En-us; ONE TOUCH 6012E Build/JDQ39) AppleWebKit/534.30 (KHTML, Like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.12975 YaBrowser/13.12.1599.12975 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; bg-bg; ONE TOUCH 6012X Build/JDQ39) AppleWebKit/534.30 (KHTML like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 6012X_orange Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; fr-fr; ALCATEL ONE TOUCH 6012X_orange Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; fr-fr; 6016E Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; ALCATEL ONE TOUCH 6016E Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; 6016X Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; ALCATEL ONE TOUCH 6016X Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; ru-ru; 6016X Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 6032A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; ru-ru; ALCATEL ONE TOUCH 6032X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-nz; ALCATEL ONE TOUCH 7040A Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; th-th; ALCATEL ONE TOUCH 7040D Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7040D Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7040E Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; it-it; ALCATEL ONE TOUCH 7041D Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7041D Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7041X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; pt-pt; ALCATEL ONE TOUCH 7041X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020A Build/JDQ39) AppleWebKit/537.36 (KHTML, Like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020A Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020D Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; es-es; ALCATEL ONE TOUCH 8020D Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020E Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020E Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Allview.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Allview.php new file mode 100644 index 0000000000..7bbcb5ea25 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Allview.php @@ -0,0 +1,11 @@ + array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; ALLVIEW P5 Build/IML74K) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us ; ALLVIEW SPEEDI Build/IMM76D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1/UCBrowser/8.5.3.246/145/355' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; AllviewCity Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; ALLVIEWSPEED Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Amazon.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Amazon.php new file mode 100644 index 0000000000..271589f88c --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Amazon.php @@ -0,0 +1,37 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; KFTT Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.4 Mobile Safari/535.19 Silk-Accelerated =true' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) Version/4.0 Kindle/3.0 (screen 600x800; rotate)' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Webkit' => '528.5+', 'Kindle' => '3.0', 'Safari' => '4.0'), 'model' => 'Kindle' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; KFOTE Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'IML74K', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; WFJWAE Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-us; KFTT Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.21 Safari/535.19 Silk-Accelerated=true' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.21 Safari/535.19 Silk-Accelerated=true' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-us; KFJWI Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.21 Safari/535.19 Silk-Accelerated=true' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-us; KFSOWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.21 Safari/535.19 Silk-Accelerated=true' => array('isMobile' => true, 'isTablet' => true), + // T720-WIFI is a tablet. + 'Mozilla/5.0 (Linux; U; Android 2.1; xx-xx; T720-WIFI Build/ECLAIR) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; KFARWI Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Silk/47.1.79 like Chrome/47.0.2526.80 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + + // Tablet. + 'Mozilla/5.0 (Linux; Android 4.4.3; KFTHWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/44.1.54 like Chrome/44.0.2403.63 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + // Desktop + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Silk/44.1.54 like Chrome/44.0.2403.63 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + + // Mobile + // The new Amazon specs are confusing. + // The problem is that KFTHWI is Kindle Fire HDX 7. So it's a tablet. + // 'Mozilla/5.0 (Linux; U; Android 4.4.3; KFTHWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/44.1.54 like Chrome/44.0.2403.63 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + // 29 mar 2017 + 'Mozilla/5.0 (Linux; Android 5.1.1; KFASWI Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Silk/48.2.2 like Chrome/48.0.2564.95 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; KFFOWI Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Silk/46.1.66 like Chrome/46.0.2490.80 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; KFGIWI Build/LVY48F) AppleWebKit/537.36 (KHTML, like Gecko) Silk/56.2.4 like Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + // Amazon Fire Phone + 'Mozilla/5.0 (Linux; U; Android 4.4.4; en-us; SD4930UR Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.60 like Chrome/37.0.2026.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Apple.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Apple.php new file mode 100644 index 0000000000..ba3691253f --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Apple.php @@ -0,0 +1,31 @@ + array( + 'iTunes/9.1.1' => array('isMobile' => false, 'isTablet' => false), + 'iTunes/11.0.2 (Windows; Microsoft Windows 8 x64 Business Edition (Build 9200)) AppleWebKit/536.27.1' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Webkit' => '420+', 'Safari' => '3.0') ), + 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '3_0', 'Webkit' => '528.18', 'Safari' => '4.0'), 'model' => 'iPhone', 'mobileGrade' => 'B' ), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '5_1_1', 'Webkit' => '534.46', 'Mobile' => '9B206', 'Safari' => '5.1'), 'model' => 'iPhone' ), + 'Mozilla/5.0 (iPod; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '6_0', 'Webkit' => '536.26', 'Mobile' => '10A403', 'Safari' => '6.0'), 'model' => 'iPod'), + 'Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X; en-us) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.80 Mobile/9B206 Safari/7534.48.3 (6FF046A0-1BC4-4E7D-8A9D-6BF17622A123)' => array('isMobile' => true, 'isTablet' => true, 'version' => array('iOS' => '5_1_1', 'Webkit' => '534.46.0', 'Chrome' => '21.0.1180.80', 'Mobile' => '9B206'), 'model' => 'iPad' ), + 'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25' => array('isMobile' => true, 'isTablet' => true, 'version' => array('iOS' => '6_0', 'Webkit' => '536.26', 'Safari' => '6.0', 'Mobile' => '10A403'), 'model' => 'iPad' ), + 'Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5' => array('isMobile' => true, 'isTablet' => true, 'version' => array('iOS' => '4_2_1', 'Webkit' => '533.17.9', 'Safari' => '5.0.2', 'Mobile' => '8C148'), 'model' => 'iPad', 'mobileGrade' => 'B' ), + 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10' => array('isMobile' => true, 'isTablet' => true, 'version' => array('iOS' => '3_2', 'Webkit' => '531.21.10', 'Safari' => '4.0.4', 'Mobile' => '7B334b'), 'model' => 'iPad', 'mobileGrade' => 'B' ), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X; da-dk) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.82 Mobile/10A523 Safari/7534.48.3' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '6_0_1', 'Webkit' => '534.46.0', 'Chrome' => '21.0.1180.82', 'Mobile' => '10A523'), 'model' => 'iPhone', 'mobileGrade' => 'A' ), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '6_0_1', 'Webkit' => '536.26', 'Safari' => '6.0', 'Mobile' => '10A523'), 'model' => 'iPhone', 'mobileGrade' => 'A' ), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X; ru-ru) AppleWebKit/536.26 (KHTML, like Gecko) CriOS/23.0.1271.100 Mobile/10B142 Safari/8536.25' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '6_1', 'Webkit' => '536.26', 'Chrome' => '23.0.1271.100', 'Mobile' => '10B142'), 'model' => 'iPhone', 'mobileGrade' => 'A' ), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '6_1_3', 'Webkit' => '536.26', 'Safari' => '6.0', 'Mobile' => '10B329'), 'model' => 'iPhone', 'mobileGrade' => 'A' ), + 'Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Coast/1.0.2.62956 Mobile/10B329 Safari/7534.48.3' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Coast' => '1.0.2.62956')), + 'CheckMyBus iOS mobile App 0.9.0 (iPhone; iPhone OS/7.1.1)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/38.0.2125.59 Mobile/12A405 Safari/600.1.4' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (iPad; CPU OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92 Version/11.1.1 Safari/605.1.15' => array('isMobile' => false, 'isTablet' => false), + 'VendorAppName/1.7.0 (iPhone; iOS 8.1.2; Scale/3.00)' => array('isMobile' => true, 'isTablet' => false, 'version' => array('iOS' => '8.1.2'), 'model' => 'iPhone', 'mobileGrade' => 'A' ), + 'Mozilla/5.0 (iPad; CPU OS 9_0 like Mac OS X) AppleWebKit/601.1.17 (KHTML, like Gecko) Version/8.0 Mobile/13A175 Safari/600.1.4' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_0 like Mac OS X) AppleWebKit/601.1.37 (KHTML, like Gecko) Version/8.0 Mobile/13A4293g Safari/600.1.4' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (iPad; CPU OS 9_0_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13A452 Safari/601.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E302 rabbit%2F1.0 baiduboxapp/0_0.0.3.7_enohpi_4331_057/1.3.11_2C2%257enohPi/1099a/4D6A2107AC77E4AD3E534E146047A21C0EC9262D6OCCBFMJOPA/1' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Archos.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Archos.php new file mode 100644 index 0000000000..ddf5d5f863 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Archos.php @@ -0,0 +1,69 @@ + array( + + 'Mozilla/5.0 (Linux; Android 6.0; Archos 97c Platinum Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (Linux; Android 4.2.2; Qilive 97R Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; Archos 50 Platinum Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2.1; fr-fr; A101IT Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; Archos 101 Neon Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Archos 101 Cobalt Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 80 TITANIUM Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.1.1; ARCHOS 101 Titanium Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 70b TITANIUM Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; de-de; Archos 80 Xenon Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Archos 79 Xenon Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 101 Titanium Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 80XSK Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS FAMILYPAD 2 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.1.1; ARCHOS 97B TITANIUM Build/JRO03H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; ARCHOS 101 XS 2 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; ARCHOS 80b PLATINUM Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Archos 70 Xenon Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; ARCHOS 97 CARBON Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 97 TITANIUMHD Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Archos 90 Neon Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 1.6; de-de; Archos5 Build/Donut) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS GAMEPAD Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Asus.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Asus.php new file mode 100644 index 0000000000..7483197e53 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Asus.php @@ -0,0 +1,33 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 3.2.1; en-us; Transformer TF101 Build/HTK75) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '3.2.1', 'Webkit' => '534.13', 'Safari' => '4.0'), 'model' => 'Transformer TF101' ), + 'Mozilla/5.0 (Linux; Android 4.1.1; Transformer Build/JRO03L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; ASUS Transformer Pad TF300T Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; fr-fr; Transformer Build/JZO54K; CyanogenMod-10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; asus_laptop Build/IMM76L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; PadFone 2 Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; PadFone 2 Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03L', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; Android 4.2.1; ME301T Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.1', 'Build' => 'JOP40D') ), + 'Mozilla/5.0 (Linux; Android 4.2.1; ME173X Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.1', 'Build' => 'JOP40D') ), + 'Mozilla/5.0 (Linux; Android 4.2.2; TF300T Build/JDQ39E) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.2', 'Build' => 'JDQ39E') ), + 'Mozilla/5.0 (Linux; Android 4.2.2; K00C Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; K00E Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; K00F Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; K00L Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; ME302KL Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; K010 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; K017 Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0; PO1MA build/LRX21V) AppelWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0(Linus; Android 4.4.2; K011 Build/KOT49H)AppleWebKit/537.36 (KHTML, like Gecko)Chrome/53.0.2785.124 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; K01E Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; P01Z Build/LRX22G; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; P027 Build/MRA58L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; P024 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.2.145.01 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; P024 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; P00C Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; ASUS_Z01QD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.185 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; K01A Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; ASUS_X00TD; Flow) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/359.0.0.288 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Blackberry.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Blackberry.php new file mode 100644 index 0000000000..b288275cf6 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Blackberry.php @@ -0,0 +1,48 @@ + array( + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.546 Mobile Safari/534.8+' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Webkit' => '534.8+', 'BlackBerry' => '6.0.0.546'), 'model' => 'BlackBerry 9300' ), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9360; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.400 Mobile Safari/534.11+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; he) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.723 Mobile Safari/534.8+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.448 Mobile Safari/534.8' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9790; en-GB) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.714 Mobile Safari/534.11+' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Webkit' => '534.11+', 'BlackBerry' => '7.1.0.714'), 'model' => 'BlackBerry 9790' ), + 'Opera/9.80 (BlackBerry; Opera Mini/7.0.29990/28.2504; U; en) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9981; en-GB) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.342 Mobile Safari/534.11+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.546 Mobile Safari/534.8+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9780; es) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.480 Mobile Safari/534.8' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9810; en-US) AppleWebKit/534.11 (KHTML, like Gecko) Version/7.0.0.583 Mobile Safari/534.11' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9860; es) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.576 Mobile Safari/534.11+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11 (KHTML, like Gecko) Version/7.1.0.523 Mobile Safari/534.11' => array('isMobile' => true, 'isTablet' => false), + 'BlackBerry8520/5.0.0.592 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/136' => array('isMobile' => true, 'isTablet' => false), + 'BlackBerry8520/5.0.0.1067 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/603' => array('isMobile' => true, 'isTablet' => false), + 'BlackBerry8520/5.0.0.1036 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/611' => array( 'isMobile' => true, 'isTablet' => false, 'version' => array('BlackBerry' => '5.0.0.1036', 'VendorID' => '611'), 'model' => 'BlackBerry8520' ), + 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9220; en) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.337 Mobile Safari/534.11+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.1+ (KHTML, like Gecko) Version/10.0.0.1337 Mobile Safari/537.1+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (BB10; Touch) /537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+' => array( 'isMobile' => true, 'isTablet' => false, 'version' => array('BlackBerry' => '10.0.9.2372') ), + 'Mozilla/5.0 (Linux; U; Android 3.2.1; en-us; Transformer TF101 Build/HTK75) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '3.2.1', 'Webkit' => '534.13', 'Safari' => '4.0'), 'model' => 'Transformer TF101' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; A200 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Webkit' => '534.30', 'Safari' => '4.0'), 'model' => 'A200' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; A500 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Webkit' => '534.30', 'Safari' => '4.0'), 'model' => 'A500' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; A501 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Webkit' => '534.30', 'Safari' => '4.0'), 'model' => 'A501' ), + 'Mozilla/5.0 (Linux; Android 4.1.1; Transformer Build/JRO03L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Webkit' => '535.19', 'Chrome' => '18.0.1025.166'), 'model' => 'Transformer' ), + 'Mozilla/5.0 (Linux; Android 4.1.1; ASUS Transformer Pad TF300T Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Webkit' => '535.19', 'Chrome' => '18.0.1025.166'), 'model' => 'Transformer Pad TF300T' ), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; fr-fr; Transformer Build/JZO54K; CyanogenMod-10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.2', 'Webkit' => '534.30', 'Safari' => '4.0', 'Build' => 'JZO54K'), 'model' => 'Transformer' ), + 'Mozilla/5.0 (Linux; Android 4.1.2; B1-A71 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.2', 'Webkit' => '535.19', 'Chrome' => '18.0.1025.166'), 'model' => 'B1-A71' ), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Acer; Allegro)' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Windows Phone OS' => '7.5', 'Trident' => '5.0', 'IE' => '9.0'), 'model' => 'Allegro' ), + // Blackberry DTEK 60 + 'Mozilla/5.0 (Linux; Android 6.0.1; BBA100-1 Build/6.0.1_0.223.0.064) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Blackberry KeyOne + 'Mozilla/5.0 (Linux; Android 8.1.0; BBB100-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.89 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; BBB100-3 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // BlackBerry Motion + 'Mozilla/5.0 (Linux; Android 7.1; BBD100-1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Blackberry KEY2 LE + 'Mozilla/5.0 (Linux; Android 8.1.0; BBE100-1 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Blackberry KEY2 + 'Mozilla/5.0 (Linux; Android 8.1.0; BBF100-9 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Blackberry DTEK 50 + 'Mozilla/5.0 (Linux; Android 6.0.1; STH100-1 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), + +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Dell.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Dell.php new file mode 100644 index 0000000000..d73b1f04ad --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Dell.php @@ -0,0 +1,15 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 1.6; en-gb; Dell Streak Build/Donut AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/ 525.20.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; hd-us; Dell Venue Build/GWK74; CyanogenMod-7.2.0) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; DELL; Venue Pro)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; Venue 8 3830 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Venue 7 3730 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Venue 7 HSPA+ Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; Venue 8 3830 Build/JSS15Q) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.2; zh-cn; Dell Streak 10 Pro Build/HTJ85B) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; DELL; Venue Pro)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 7.0.1; en-US; Dell Streak 7 Build/FRF91) AppleWebKit/51.0 (KHTML, like Gecko) Version/4.0 Mobile Safari/51.0' => array('isMobile' => true, 'isTablet' => true) + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Google.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Google.php new file mode 100644 index 0000000000..46c4216241 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Google.php @@ -0,0 +1,24 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; Nexus 4 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.40 Mobile Safari/537.31 OPR/14.0.1074.54070' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.2.2', 'Build' => 'JDQ39', 'Webkit' => '537.31', 'Opera' => '14.0.1074.54070') ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Nexus 4 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.2.2', 'Chrome' => '26.0.1410.58')), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Galaxy Nexus - 4.1.1 - API 16 - 720x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2; Nexus 7 Build/JOP40C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZ054K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.2', 'Chrome' => '18.0.1025.166') ), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; cs-cz; Nexus S Build/JZO54K; CyanogenMod-10.0.0) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JWR66Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android; en_us; Nexus 7 Build/) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 NetFrontLifeBrowser/2.3 Mobile (Dragonfruit)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; Nexus 5 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 momoWebView/6.3.1 android/404(Nexus 5;android 5.1;zh_CN;10;netType/1)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JWR66Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1; Pixel XL Build/NDE63H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1; Pixel Build/NDE63H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; Pixel C Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; Pixel C Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 Build/OPM2.171026.006.G1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HP.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HP.php new file mode 100644 index 0000000000..4f8b14a821 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HP.php @@ -0,0 +1,21 @@ + array( + 'Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.5; U; en-GB) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.83 Safari/534.6 TouchPad/1.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; HP Slate 7 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; HP Slate 7 Build/JRO03H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; HP 8 Build/1.0.7_WW-FIR-13) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; HP Slate 10 HD Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; Android 4.4.2; HP Slate 8 Pro Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; Slate 21 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Safari/537.36 OPR/22.0.1485.78487' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; Android 4.3; HP SlateBook 10 x2 PC Build/4.3-17r20-03-23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true + ), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HTC.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HTC.php new file mode 100644 index 0000000000..de60163d8a --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/HTC.php @@ -0,0 +1,385 @@ + array( + 'Mozilla/5.0 (X11; Linux x86_64; Z520m; en-ca) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24' => array('isMobile' => true, 'isTablet' => false), + 'HTC_Touch_HD_T8282 Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 1.5; en-us; ADR6200 Build/CUPCAKE) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1; xx-xx; Desire_A8181 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; en-gb; HTC Desire Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; fr-fr; HTC Desire Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; en-dk; Desire_A8181 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; xx-xx; 001HT Build/FRF91) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; xx-xx; HTCA8180/1.0 Android/2.2 release/06.23.2010 Browser/WAP 2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.2; de-at; HTC Desire Build/FRG83G) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.2; en-sk; Desire_A8181 Build/FRG83G) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; HTC/DesireS/1.07.163.1 Build/GRH78C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-lv; HTC_DesireZ_A7272 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; ADR6300 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-gb; HTC/DesireS/2.10.161.3 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireS_S510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; Inspire 4G Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; de-de; HTC Explorer A310e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-gb; HTC_ChaCha_A810e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; nl-nl; HTC_DesireHD_A9191 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC Desire S Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-au; HTC Desire Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; de-de; HTC_DesireHD Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ua; HTC_WildfireS_A510e Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; HTC Vision Build/GRI40; ILWT-CM7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; HTC_GOF_U/1.05.161.1 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; hu-hu; HTC Sensation Z710e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC Sensation XE with Beats Audio Z715e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; pl-pl; EVO3D_X515m Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC_One_S Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC_One_V Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC_A320e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; zh-tw; HTC Desire V Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; PG86100 Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-nl; SensationXE_Beats_Z715e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; ADR6425LVW 4G Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; cs-ee; Sensation_Z710e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; HTC Evo 4G Build/MIUI) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; Desire HD Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-my; HTC_One_X Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; it-it; IncredibleS_S710e Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; fr-fr; HTC_Desire_S Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC Butterfly Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; EVO Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTCSensation Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; GT-S6312 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC 7 Mozart T8698; QSD8x50)' => array( + 'isMobile' => true, 'isTablet' => false, 'version' => array('IE' => '9.0', 'Windows Phone OS' => '7.5', 'Trident' => '5.0'), 'model' => '7 Mozart T8698', + ), + 'Mozilla/5.0 (Linux; U; Android 3.2.1; en-gb;HTC_Flyer_P512 Build/HTK75C) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (Linux; U; Android 3.1; zh-tw; HTC PG09410 Build/HMJ15) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 HTC MOZART)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mondrian T8788)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mozart T8698)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mozart)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Mozart; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Pro T7576)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Pro)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Schubert T9292)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Surround)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Trophy T8686)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; 7 Trophy)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Eternity)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Gold)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; HD2 LEO)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; HD2)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; HD7 T9292)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; HD7)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; iPad 3)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; LEO)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Mazaa)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Mondrian)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Mozart T8698)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Mozart)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; mwp6985)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; PC40100)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; PC40200)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; PD67100)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; PI39100)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; PI86100)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar 4G)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar C110e)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar C110e; 1.08.164.02)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar C110e; 2.05.164.01)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar C110e; 2.05.168.02)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Radar; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Schuber)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Schubert T9292)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Schubert)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Spark)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Surround)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; T7575)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; T8697)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; T8788)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; T9295)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; T9296)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; TITAN X310e)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Torphy T8686)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; X310e)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC_blocked; T8788)' => array( + 'isMobile' => true, 'isTablet' => false, 'version' => array('IE' => '9.0', 'Windows Phone OS' => '7.5', 'Trident' => '5.0'), 'model' => 'T8788', + ), + + 'Mozilla/5.0 (Linux; Android 4.0.4; HTC One S Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; HTC One X Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-th; HTC One V Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; HTC One X Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-id; HTC One X Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One S Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-at; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.123 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.123 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One X Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; es-pe; HTC One V Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; HTC One X Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 Maxthon/4.0.4.1000' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19 AlexaToolbar/alxf-2.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One S Build/IML74K) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; de-de; HTC One Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 OPR/14.0.1074.58201' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-es; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.64 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.64 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.64 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39E) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One XL Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Mobile Safari/537.36 OPR/15.0.1162.60140' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.24 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'HTC One X Linux/3.0.13 Android/4.1.9 Release/10.12.2012 Browser/AppleWebKit534.30 Profile/MIDP-2.0 Configuration/CLDC-1.1 Mobile Safari/534.30 Android 4.0.1;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One 801e Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; HTC One X Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Mobile Safari/537.36 OPR/15.0.1162.61541' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One XL Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X+ Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC One X Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30/4.05d.1002.m7' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-in; HTC One V Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC One X Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MicroMessenger/5.0.1.352' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; HTC One X Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; HTC One Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One SV Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One mini Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; HTC One Build/IMM76D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One 801e Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-ch; HTC One Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; nl-nl; HTC One X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC One S Build/IML74K) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17 T5/2.0 baidubrowser/3.1.6.4 (Baidu; P1 4.0.3)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X+ Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; HTC One 801e Build/JSS15J) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.4.1.362 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4; HTC One Build/KRT16S.H5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One SV Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.1; ru-ru; HTC One Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; ru-ru; HTC One 801e Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One 801e Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One mini Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.12975 YaBrowser/13.12.1599.12975 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4; HTC One Build/KRT16S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; HTC One Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One X Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One X Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JWR66Y.H1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; de-at; HTC One Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X+ Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One dual sim Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; HTC One S Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One max Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One mini Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One 801e Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; HTC One Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MicroMessenger/5.2.380' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X+ Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; HTC One X Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; it-it; HTC One S Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-kw; HTC One X+ Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One max Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 MicroMessenger/5.3.0.49_r693790.420' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru; HTC One V Build/IML74K) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.7.5.418 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 MicroMessenger/5.2.1.381' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One mini Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; ru-ru; HTC One mini Build/KOT49H) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru; HTC One V Build/IML74K) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.8.0.435 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One 801e Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; HTC One X - 4.2.2 - API 17 - 720x1280 Build/JDQ39E) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X+ Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.128 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.128 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.128 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One_M8 Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; HTC One VX Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.76 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One V Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One dual sim Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One dual sim Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36 OPR/22.0.1485.78487' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X+ Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One_M8 Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One 801e Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One 801e Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36 OPR/22.0.1485.81203' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One 801e Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; HTC One S Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-tw; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One_M8 Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC One V Build/IML74K) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.9.2.467 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One mini Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; HTC One_M8 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One dual sim Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.72 Mobile Safari/537.36 OPR/19.0.1340.69721' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One_M8 Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One SV Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 ACHEETAHI/2100050056' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One_M8 Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JWR66Y.H1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One SV Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 [FBAN/FB4A;FBAV/21.0.0.23.12;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; ru-si; HTC One X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MicroMessenger/6.0.0.67_r853700.483 NetType/WIFI' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 [FBAN/FB4A;FBAV/22.0.0.15.13;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-US; HTC One X Build/JRO03C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/10.0.1.512 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One Build/KTU84P.H1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 [FBAN/FB4A;FBAV/22.0.0.15.13;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 [FBAN/FB4A;FBAV/22.0.0.15.13;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One SV Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 [FBAN/FB4A;FBAV/22.0.0.15.13;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-tw; HTC One X+ Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 BingWeb/5.2.0.20140710' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; HTC One Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-mx; HTC One S Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 [FBAN/FB4A;FBAV/23.0.0.22.14;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.3; es-es; HTC One 801e Build/KTU84L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X+ Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.69 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC One S Build/JRO03C) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-th; HTC One Build/KOT49H) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; es-ar; HTC One X Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One_M8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-us; HTC One X+ Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; es-mx; HTC One S Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/24.0.0.30.15;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; HTC One Build/KTU84L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.89 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One dual sim Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.89 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/25.0.0.19.30;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.1; HTC One_M8 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/37.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/25.0.0.19.30;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.89 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; HTC One_M8 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.109 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; HTC One X Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.109 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.1; HTC One_M8 Build/LRX22C.H5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.109 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel Build/OPR6.170623.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.125 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1; Pixel XL Build/NDE63H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + ), + // https://github.com/serbanghita/Mobile-Detect/issues/815 + 'Pixel' => array( + 'Mozilla/5.0 (Linux; Android 10; Pixel) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 9; Pixel XL Build/PQ3A.190801.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.149 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/263.0.0.46.121;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; Pixel XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.96 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; PIXEL 2 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 2 XL Build/QQ2A.200305.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.132 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/262.0.0.34.117;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.9805.620 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 2 Build/QQ1A.191205.008; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.149 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/261.0.0.52.126;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; Pixel C Build/OPM8.190405.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.132 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; Pixel Build/QP1A.191005.007.A3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.132 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/261.0.0.52.126;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 3 Build/QQ2A.200305.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.149 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/263.0.0.46.121;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 3a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Mobile Safari/537.36 OPR/57.1.2830.52480' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 3a XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 9; Pixel 3 XL Build/PQ3A.190801.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/76.0.3809.89 Mobile Safari/537.36 T7/11.21 SP-engine/2.17.0 baiduboxapp/11.21.0.10 (Baidu; P1 9)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Pixel 4 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 11; Pixel 4a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ) +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Huawei.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Huawei.php new file mode 100644 index 0000000000..87cde316df --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Huawei.php @@ -0,0 +1,34 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; bg-bg; Ideos S7 Build/ERE27) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Ideos S7 Build/ERE27) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; lt-lt; U8660 Build/HuaweiU8660) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; ru-ru; HUAWEI-U8850 Build/HuaweiU8850) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 3.2; pl-pl; MediaPad Build/HuaweiMediaPad) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.2; nl-nl; HUAWEI MediaPad Build/HuaweiMediaPad) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'HUAWEI_T8951_TD/1.0 Android/4.0.4 (Linux; U; Android 4.0.4; zh-cn) Release/05.31.2012 Browser/WAP2.0 (AppleWebKit/534.30) Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; ar-eg; MediaPad 7 Youth Build/HuaweiMediaPad) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-cn; HW-HUAWEI_C8815/C8815V100R001C541B135; 540*960; CTC/2.0) AppleWebKit/534.30 (KHTML, like Gecko) Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; HW-HUAWEI_C8813D/C8813DV100R001C92B172; 480*854; CTC/2.0) AppleWebKit/534.30 (KHTML, like Gecko) Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; HW-HUAWEI_Y300C/Y300CV100R001C92B168; 480*800; CTC/2.0) AppleWebKit/534.30 (KHTML, like Gecko) Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; id-id; HUAWEI Y330-U11 Build/HuaweiY330-U11) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16 Chrome/33.0.0.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1.1; HUAWEI M2-A01L Build/HUAWEIM2-A01L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; HUAWEI GRA-L09 Build/HUAWEIGRA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; FRD-L09 Build/HUAWEIFRD-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.0; DUK-AL20 Build/HUAWEIDUK-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044054 Mobile Safari/537.36 V1_AND_SQ_7.5.8_818_YYB_D QQ/7.5.8.3490 NetType/WIFI WebP/0.3.0 Pixe' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; BAH-L09 Build/HUAWEIBAH-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; BAH-W09 Build/HUAWEIBAH-W09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; WAS-LX3 Build/HUAWEIWAS-LX3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 [FB_IAB/Orca-Android;FBAV/162.0.0.19.90;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.0.0; CMR-AL19 Build/HUAWEICMR-AL19) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; AGS-L09 Build/HUAWEIAGS-L09; xx-xx) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.0.0; EDI-AL10 Build/HUAWEIEDISON-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.121 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; cs-cz; HUAWEI G510-0200 Build/HuaweiG510-0200) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; KOB2-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.166 Safari/537.36 OPR/65.1.3381.61266' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; BG2-U03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; BG2-W09 Build/HuaweiBAGGIO2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + +); + diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/LG.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/LG.php new file mode 100644 index 0000000000..c13df40d56 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/LG.php @@ -0,0 +1,37 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; LG-VS410PP Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; en-us; LG-P509 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.2; pt-br; LG-P350f Build/FRG83G) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; LG-P500 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; LS670 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; LG-E510 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; VS910 4G Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; LG-P700 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; LG-F160S Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; LG-E610v/V10f Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; LG-E612 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; LG-F180K Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; LG-V500 Build/JDQ39B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; LG-LW770 Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; LG-V510 Build/KOT49H.L004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG E-900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-C900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-C900k)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-E900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-E900; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-E900h)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; LG; LG-Optimus 7)' => array('isMobile' => true, 'isTablet' => false), + // @ref: http://ja.wikipedia.org/wiki/L-06C + 'Mozilla/5.0 (Linux; U; Android 3.0.1; ja-jp; L-06C Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.0; en-us; LG-V900 Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-gb; LG-V700 Build/KOT49I.A1403851714) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; LG-V500 Build/KOT49I.V50020d) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LG-V410/V41010d Build/KOT49I.V41010d) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.0.0; LM-G710 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lava.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lava.php new file mode 100644 index 0000000000..95c3786884 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lava.php @@ -0,0 +1,23 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Iris 349 Build/MocorDroid2.3.5) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; iris402+ Build/iris402+) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; IRIS402 Build/LAVAIRIS402) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; iris405 Build/LAVAIRIS405) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; IRIS_501 Build/LAVAIRIS501) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; iris402e Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; iris503e Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'UCWEB/2.0 (Linux; U; Opera Mini/7.1.32052/30.3697; en-US; IRIS402) U2/1.0.0 UCBrowser/9.1.1.420 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'UCWEB/2.0 (MIDP-2.0; U; Adr 4.2.2; en-US; IRIS402) U2/1.0.0 UCBrowser/9.1.1.420 U2/1.0.0 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'UCWEB/2.0 (Linux; U; Opera Mini/7.1.32052/30.3697; en-US; IRIS355) U2/1.0.0 UCBrowser/9.1.1.420 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; iris356 Build/irisIRIS356) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.5.0.360 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'UCWEB/2.0 (Linux; U; Opera Mini/7.1.32052/30.3697; en-US; iris356) U2/1.0.0 UCBrowser/9.0.2.389 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; iris500 Build/iris500) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; iris700 Build/iris700) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; QPAD E704 Build/JDQ39) AppleWebKit/537.36 (KHTML like Gecko) Chrome/36.0.1985.131 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2; xx-xx; IvoryS Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-US; E-TAB IVORY Build/E702) AppleWebKit/534.31 (KHTML, like Gecko) UCBrowser/9.3.0.321 U3/0.8.0 Mobile Safari/534.31' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; tr-tr; E-TAB Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true) + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Leader.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Leader.php new file mode 100644 index 0000000000..fbdf4b5cdc --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Leader.php @@ -0,0 +1,6 @@ + array('isMobile' => true, 'isTablet' => true) + ) +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lenovo.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lenovo.php new file mode 100644 index 0000000000..99cb2584fa --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Lenovo.php @@ -0,0 +1,88 @@ + array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; IdeaTab_A1107 Build/MR1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.3; IdeaTab A2107A-H Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-au; ThinkPad Tablet Build/ThinkPadTablet_A400_03) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'UCWEB/2.0 (Linux; U; Opera Mini/7.1.32052/30.3697; en-US; IdeaTabA1000-G) U2/1.0.0 UCBrowser/9.2.0.419 Mobile' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; IdeaTabA1000-F Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.1; Lenovo A3000-H Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.117 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; IdeaTab A3000-F Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.360' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1; zh-cn; Lenovo-A3000-H/S100) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.1 Mobile Safari/534.300' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; es-us; IdeaTab A3000-F Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.3; IdeaTab A2107A-H Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; IdeaTab A2107A-H Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-es; IdeaTabA2109A Build/JRO03R) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; nl-nl; IdeaTabA2109A Build/JRO03R) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; IdeaTab_A1107 Build/MR1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.300' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; IdeaTab S6000-H Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; IdeaTab S6000-F Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; Lenovo B8000-F Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2;it-it; Lenovo B8000-F/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; it-it; Lenovo B6000-F/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.2.2 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; Lenovo B6000-F Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; IdeaPadA10 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.1.2; Ideapad K1 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; de-de; IdeaPad A1 Build/GRK393; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.3; Lenovo B8080-H Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; hu-hu; Lenovo A3500-FL Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; Lenovo A7600-F Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A5500-F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.131 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Lenovo A390 Linux/3.0.13 Android/4.4.2 Release/04.03.2013 Browser/AppleWebKit534.30 Profile/MIDP-2.0 Configuration/CLDC-1.1 Mobile Safari/534.30 Android 4.0.1;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; Lenovo TAB 2 A7-30F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.84 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A319 Build/MocorDroid4.4.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1; Lenovo YT3-X90L Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.105 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-X103F Build/LenovoTB-X103F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-X304F Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-8703F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; Lenovo P2a42 Build/NRD90N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo P2a42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-X304L Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Tab2A7-10F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36 ACHEETAHI/1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB2-X30L Build/LenovoTB2-X30L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + // https://github.com/serbanghita/Mobile-Detect/issues/777 + 'Mozilla/5.0(Linux;Android 6.0.1;Lenovo YT3-X50L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30F Build/LenovoTB2-X30F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30F Build/LenovoTB2-X30F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.121 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30M_PRC_YZ_A Build/LenovoTB2-X30M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/10.4 light/1.0 baiduboxapp/10.4.5.11 (Baidu; P1 5.1.1)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.1(Linux; U; Android 5.0; zh-cn; Lenovo YT3-X50M Build/LMY47V) AppleWebKit/537.36(KHTML, like Gecko) Version/4.0 Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo YT3-X50F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.154 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Tab2A7-20F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36 hsp' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; Lenovo A5500-HV Build/JDQ39; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/7.9 baiduboxapp/9.0.0.10 (Baidu; P1 4.2.2)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0; zh-cn; LNV-Lenovo A5500/A5500_S165_161206; 1280x720; CTC/2.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/37.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo YT-X703F Build/S100) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo YT-X703L Build/S100; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Safari/537.36 clicash_android v=1.671' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-8703N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.154 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-8704N Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/10.6 baiduboxapp/10.6.5.10 (Baidu; P1 7.1.1)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-8704F Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/10.5 baiduboxapp/10.5.5.10 (Baidu; P1 7.1.1)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730M Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730F Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/10.7 baiduboxapp/10.7.5.10 (Baidu; P1 6.0)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730X Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-X704F Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.100 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; Lenovo TB-X104F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-X70F Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 T7/10.3 baiduboxapp/10.3.6.13 (Baidu; P1 6.0)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; Lenovo TB3-X70F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.9.4.974 UWS/2.13.2.100 Mobile Safari/537.36 AliApp(DingTalk/5.0.5) com.alibaba.android.rimet/1272' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; Lenovo TB-X705F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-8504F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Lenovo TB-X704L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 11; Lenovo TB-J606F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; Lenovo TB-X606F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; Lenovo TB-X306X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.74 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 12; Lenovo YT-J706X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mi.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mi.php new file mode 100644 index 0000000000..0503451ba6 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mi.php @@ -0,0 +1,27 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 4.2; xx-xx; HM NOTE 1W Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 MobilSafari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.1; zh-cn; MI-ONE Plus Build/ITL41D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI 2SC Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI 2S Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-tw; MI 1S Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.8; zh-cn; xiaomi2 Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/4.4 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-es; MI 2A Build/miui.es JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.1; zh-cn; MI 3 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; MI 1S Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; MI 3W Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; HM 1SC Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; HM 1SW Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 XiaoMi/MiuiBrowser/2.0.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; HM NOTE 1W Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 XiaoMi/MiuiBrowser/2.0.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; MI-ONE C1 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.4; en-us; MI 4W Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 XiaoMi/MiuiBrowser/2.0.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4; MI PAD Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/71.0.3578.141 Safari/534.24 XiaoMi/MiuiBrowser/12.6.6-gn' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; POCOPHONE F1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; MI 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Redmi Note 9s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; en-gb; Redmi Note 5A Prime Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 12; tr-tr; Redmi Note 10 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.14.1-gn' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Microsoft.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Microsoft.php new file mode 100644 index 0000000000..ee05e28bf5 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Microsoft.php @@ -0,0 +1,77 @@ + array( + // @See https://github.com/serbanghita/Mobile-Detect/issues/564 + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586' => array('isMobile' => false, 'isTablet' => false), + // Surface tablet + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)' => array('isMobile' => true, 'isTablet' => true, 'version' => array('IE' => '10.0', 'Windows NT' => '6.2', 'Trident' => '6.0') ), + // Ambiguous. + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0)' => array('isMobile' => true, 'isTablet' => false), + // Ambiguous. + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)' => array('isMobile' => true, 'isTablet' => false), + // http://www.whatismybrowser.com/developers/unknown-user-agent-fragments + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch; ARMBJS)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; MASMJS)' => array('isMobile' => false, 'isTablet' => false), + + // Thanks to Jonathan Donzallaz! + // Firefox (nightly) in metro mode on Dell XPS 12 + 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:25.0) Gecko/20130626 Firefox/25.0' => array('isMobile' => false, 'isTablet' => false), + // Firefox in desktop mode on Dell XPS 12 + 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0' => array('isMobile' => false, 'isTablet' => false), + // IE10 in metro mode on Dell XPS 12 + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; MDDCJS)' => array('isMobile' => false, 'isTablet' => false), + // IE10 in desktop mode on Dell XPS 12 + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MDDCJS)' => array('isMobile' => false, 'isTablet' => false), + // Opera on Dell XPS 12 + 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.130' => array('isMobile' => false, 'isTablet' => false), + // Chrome on Dell XPS 12 + 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + // Google search app from Windows Store + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; MDDCJS; WebView/1.0)' => array('isMobile' => false, 'isTablet' => false), + + // Nokia Lumia Tests. + // There are important because of Windows Continuum. + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; Microsoft; Lumia 640 XL LTE)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 620)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 822)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 430 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 435) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 532) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 535) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 535) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537 BMID/E679DAAB6F' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 640 LTE) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 1520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537 UCBrowser/4.2.1.541 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 530) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 620) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 625) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 630 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 630) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 735) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 820; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 830) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 925) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 930) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.2; ARM; Trident/7.0; Touch; rv:11.0; WPDesktop; Lumia 635) like Gecko' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 640 Dual SIM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 625) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 635) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 830) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14295' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 930) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14295' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 530 Dual SIM) like Gecko' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Windows NT 10.0; ARM; Lumia 950 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 10.0; ARM; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 10.0; ARM; Lumia 930) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 10.0; ARM; Lumia 730 Dual SIM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Motorola.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Motorola.php new file mode 100644 index 0000000000..1782a15444 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Motorola.php @@ -0,0 +1,54 @@ + array( + 'MOT-W510/08.11.05R MIB/BER2.2 Profile/MIDP-2.0 Configuration/CLDC-1.1 EGE/1.0 UP.Link/6.3.0.0.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.2; zh-cn; ME722 Build/MLS2GC_2.6.0) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; DROIDX Build/4.5.1_57_DX8-51) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; MB855 Build/4.5.1A-1_SUN-254_13) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; es-us; MB526 Build/4.5.2-51_DFL-50) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-ca; MB860 Build/4.5.2A-51_OLL-17.8) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; MOT-XT535 Build/V1.540) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; ko-kr; A853 Build/SHOLS_U2_05.26.3; CyanogenMod-7.1.2) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.1; en-us; Xoom Build/HMJ25) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; DROID RAZR 4G Build/6.7.2-180_DHD-16_M4-31) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; Xoom Build/IMM76L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; pt-br; XT687 Build/V2.27D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.0.4', 'Webkit' => '534.30', 'Safari' => '4.0'), 'model' => 'XT687' ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; MOT-XT910 Build/6.7.2-180_SPU-19-TA-11.6) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT910 Build/9.8.2O-124_SPUL-17) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT915 Build/2_32A_2031) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT919 Build/2_290_2017) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.64 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT925 Build/9.8.2Q-50-XT925_VQLM-20) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT907 Build/9.8.1Q-66) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT901 Build/9.8.2Q-50_SLS-13) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; DROID BIONIC Build/9.8.2O-72_VZW-22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 4.4.2; XT1022 Build/KXC20.82-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.4; en-in; XT1022 Build/KXC21.5-40) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16'=> array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; XT1025 Build/KXC20.82-13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; XT1052 Build/KLA20.16-2.16.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; XT1052 Build/13.9.0Q2.X_83) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; XT1053 Build/13.9.0Q2.X_61) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; XT1053 Build/13.9.0Q2.X_55) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; XT1056 Build/13.9.0Q2.X-116-MX-17-6-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.64 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; XT1031 Build/KXB20.9-1.10-1.18-1.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; XT1032 Build/KXB21.14-L1.40) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; de-de; XT1032 Build/KLB20.9-1.10-1.24-1.1) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.16' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; XT1034 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; XT1034 Build/14.10.0Q3.X-84-16) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; XT1035 Build/14.10.0Q3.X-23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.3; XT1039 Build/KXB21.14-L1.31) AppleWebKit/537.36 (KHTML like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; XT919 Build/2_290_2002) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT919 Build/2_290_2004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; XT920 Build/2_290_2014) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; XT920 Build/2_310_2014) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; XT905 Build/7.7.1Q_GCIRD-16) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; XT908 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; XT897 Build/7.7.1Q-6_SPR-ASANTI_LE-18) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; XT1032 Build/LXB22.46-28.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1.1; Moto E Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; XT1021 Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0; XT1092 Build/MPE24.49-18) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mpman.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mpman.php new file mode 100644 index 0000000000..11f94aa62d --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Mpman.php @@ -0,0 +1,9 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; MPDC703 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; fr-fr; MPDC706 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; MPQC1010 Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true) + ) + +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nexus.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nexus.php new file mode 100644 index 0000000000..6c373cf72c --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nexus.php @@ -0,0 +1,23 @@ + array( + // Tablets + 'Mozilla/5.0 (Linux; Android 6.0; Nexus 9 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 9 Build/LMY48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; Nexus 9 Build/N4F26M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; Nexus 9 Build/NRD91N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 QBWebViewUA/2 QBWebViewType/1 WKType/1' => array('isMobile' => true, 'isTablet' => true), + // Phones + 'Mozilla/5.0 (Linux; U; Android 7.1.1; zh-CN; Nexus 6 Build/N6F27E) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/4.0 Chrome/40.0.2214.89 UCBrowser/12.8.6.1274 Mobile Safari/537.36 AliApp(TUnionSDK/0.1.20.3)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.92 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; Galaxy Nexus Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/5.0 Mb2345Browser/9.4.1oem Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse' => array('isMobile' => true, 'isTablet' => false), + 'E-Mobile7/7.0.37.20200806 (Linux;U;Android 10;Nexus One Build.FRG83) AppleWebKit/553.1(KHTML,like Gecko) Version/4.0 Mobile Safari/533.1 Language/zh Mode/PCKM80 DeviceBrand/OPPO IMEI/fa3d88953a07b469 Qiyuesuo/physicalSDK' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 5.1 en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 baidubrowser/4.5.0.0 (Baidu; P1 5.1)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6 Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/76.0.3809.89 Mobile Safari/537.36 T7/11.21 SP-engine/2.17.0 baiduboxapp/11.21.0.10 (Baidu; P1 6.0.1)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.4; en-us; Nexus 4 Build/JOP24G) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + ) + +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nokia.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nokia.php new file mode 100644 index 0000000000..f9a5026670 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Nokia.php @@ -0,0 +1,87 @@ + array( + 'Nokia200/2.0 (12.04) Profile/MIDP-2.1 Configuration/CLDC-1.1 UCWEB/2.0 (Java; U; MIDP-2.0; en-US; nokia200) U2/1.0.0 UCBrowser/8.9.0.251 U2/1.0.0 Mobile UNTRUSTED/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Nokia6303iclassic/5.0 (06.61) Profile/MIDP-2.1 Configuration/CLDC-1.1 Mozilla/5.0 AppleWebKit/420+ (KHTML, like Gecko) Safari/420+' => array('isMobile' => true, 'isTablet' => false), + 'nokian73-1/UC Browser7.8.0.95/69/400 UNTRUSTED/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Nokia2760/2.0 (06.82) Profile/MIDP-2.1 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0' => array('isMobile' => true, 'isTablet' => false), + 'NokiaN70-1/5.0737.3.0.1 Series60/2.8 Profile/MIDP-2.0 Configuration/CLDC-1.1/UC Browser7.8.0.95/27/352' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (S60V3; U; ru; NokiaN73) AppleWebKit/530.13 (KHTML, like Gecko) UCBrowser/8.6.0.199/28/444/UCWEB Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (S60V3; U; ru; NokiaC5-00.2)/UC Browser8.5.0.183/28/444/UCWEB Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (S60V3; U; ru; NokiaC5-00.2) AppleWebKit/530.13 (KHTML, like Gecko) UCBrowser/8.7.0.218/28/352/UCWEB Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Series40; NokiaC3-00/08.63; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/2.2.0.0.33' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Series 60; Opera Mini/7.0.31380/28.2725; U; es) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Opera Mini' => '7.0.31380', 'Presto' => '2.8.119')), + 'Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaC7-00/025.007; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.37 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaX7-00/022.014; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.37 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 NokiaE6-00/111.140.0058; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/535.1 (KHTML, like Gecko) NokiaBrowser/8.3.1.4 Mobile Safari/535.1 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 NokiaC6-01/111.040.1511; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/535.1 (KHTML, like Gecko) NokiaBrowser/8.3.1.4 Mobile Safari/535.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 NokiaC6-01; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.4.2.6 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 Nokia700/111.030.0609; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.4.2.6 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 Nokia700/111.020.0308; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.4.1.14 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 NokiaN8-00/111.040.1511; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/535.1 (KHTML, like Gecko) NokiaBrowser/8.3.1.4 Mobile Safari/535.1 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Symbian/3; Series60/5.3 Nokia701/111.030.0609; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.4.2.6 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/3.83; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 Nokia6120ci/7.02; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/7.10; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaE66-1/510.21.009; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaE71-1/110.07.127; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaN95-3/20.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaE51-1/200.34.36; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaE63-1/500.21.009; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaN82/10.0.046; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-1/052.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.2' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-1/@version@; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.26 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaC5-00/031.022; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.3.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaC5-00.2/081.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.32 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2 NokiaN79-1/32.001; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2 Nokia6220c-1/06.101; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaC5-00.2/071.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.26 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE72-1/081.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.32 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaC5-00/061.005; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.2 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaX6-00/40.0.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.33 Mobile Safari/533.4 3gpp-gb' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 Nokia5800d-1/60.0.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.33 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaC5-03/12.0.023; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.9 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 Nokia5228/40.1.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.7.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 Nokia5230/51.0.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.33 Mobile Safari/533.4 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 Nokia5530c-2/32.0.007; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.9 3gpp-gba' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/21.0.045; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.4' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-4/30.0.004; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.28 3gpp-gba' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Symbian' => '9.4', 'Webkit' => '533.4', 'NokiaBrowser' => '7.3.1.28'), 'model' => 'NokiaN97-4' ), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; 7 Mozart T8698)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; 710)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; 800)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; 800C)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; 800C; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; 900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; HD7 T9292)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; LG E-900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 610)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710; T-Mobile)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710; Vodafone)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800) UP.Link/5.1.2.6' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800; SFR)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800; T-Mobile)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800; vodafone)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; Lumia 800c)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; Lumia 920)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)' => array('isMobile' => true, 'isTablet' => false, 'version' => array('IE' => '10.0', 'Windows Phone OS' => '8.0', 'Trident' => '6.0'), 'model' => 'Lumia 920' ), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; lumia800)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Nokia 610)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Nokia 710)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Nokia 800)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Nokia 800C)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Nokia 900)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; Nokia)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; SGH-i917)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Nokia; TITAN X310e)' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Windows Phone OS' => '7.5', 'Trident' => '5.0'), 'model' => 'TITAN X310e' ), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 635) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10166' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 535 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' => array('isMobile' => true, 'isTablet' => false), + 'NokiaC3-01.5/5.0 (07.58) Profile/MIDP-2.1 Configuration/CLDC-1.1 Mozilla/5.0 AppleWebKit/420+ (KHTML, like Gecko) Safari/420+' => array('isMobile' => true, 'isTablet' => false) + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Onda.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Onda.php new file mode 100644 index 0000000000..c679b47819 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Onda.php @@ -0,0 +1,13 @@ + array( + 'Mozilla/5.0 (Linux; Android 4.2.2; V975i Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.108 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Android; Tablet; rv:37.0) Gecko/37.0 Firefox/37.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; V975m Core4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.3; fr-fr; V975m Core4 Build/JSS15J) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Safari/537.16' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.3; V975m Core4 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; V812 Core4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; V10 4G Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.1.628.01 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ) + +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Others.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Others.php new file mode 100644 index 0000000000..76fedd01b8 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Others.php @@ -0,0 +1,592 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; E1C Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; id-id; T3C Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Ainol' => array( + + 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Ainol Novo8 Advanced Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; Novo10 Hero Build/20121115) AppleWebKit/535.19 (KHTML like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; es-es; novo9-Spark Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + ), + 'AllFine' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; FINE7 GENIUS Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Amoi' => array( + 'Amoi 8512/R18.0 NF-Browser/3.3' => array('isMobile' => true, 'isTablet' => false, 'model' => '8512'), + ), + + 'Arnova' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; fr-fr; AN9G2I Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'AudioSonic' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-au; T-17B Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + + 'Blaupunkt' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; Endeavour 800NG Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + ), + + 'Broncho' => array( + + 'Mozilla/5.0 (Linux; U; Android 2.2; es-es; Broncho N701 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + + ), + + // @ref: http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bq' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; bq Livingstone 2 Build/1.1.7 20121018-10:33) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; bq Edison Build/1.1.10-1015 20121230-18:00) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.3; Maxwell Lite Build/v1.0.0.ICS.maxwell.20120920) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; zh-tw; bq Maxwell Plus Build/1.0.0 20120913-10:39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; Aquaris E10 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; Aquaris M10 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Aquaris M10 FHD Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; Aquaris M8 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.4; Aquaris E5 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0; Aquaris E5 HD Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0; Aquaris_M4.5 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; Aquaris X5 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.91 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; Aquaris E4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; Aquaris M5 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Captiva' => array( + 'Opera/9.80 (X11; Linux zvav; U; de) Presto/2.8.119 Version/11.10 Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; CAPTIVA PAD 10.1 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + ), + + 'Casio' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; C771 Build/C771M120) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + ), + + 'ChangJia' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.4; pt-br; TPC97113 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; TPC7102 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true) + + ), + + + 'Celkon' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; Celkon CT 910+ Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-in; CT-1 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'CELKON.C64/R2AE SEMC-Browser/4.0.3 Profile/MIDP-2.0 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Celkon A125 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-US; Celkon*A86 Build/Celkon_A86) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 UCBrowser/8.7.0.315 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Celkon A.R 40 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + ), + + // @ref: http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'Coby' => array( + 'Mozilla/5.0 (Linux; U; Android 2.2; en-us; MID7010 Build/FRF85B) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; MID7048 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; MID8042 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Concorde' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; hu-hu; ConCorde Tab T10 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; hu-hu; ConCorde tab PLAY Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Cresta' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; nl-nl; CRESTA.CTP888 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Cube' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; CUBE U9GT 2 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Danew' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.3; es-es; Dslide 700 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array( 'Android' => '4.0.3', 'Build' => 'IML74K', 'Webkit' => '534.30', 'Safari' => '4.0' ), 'model' => 'Dslide 700' ) + + ), + + 'DanyTech' => array( + 'Mozilla/5.0 (Linux; Android 4.2.2; Genius Tab Q4 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + + + 'Digma' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; iDx10 3G Build/ICS.b02ref.20120331) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'DPS' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; DPS Dream 9 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'ECS' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; it-it; TM105A Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'IMM76D', 'Webkit' => '534.30')) + ), + + 'Eboda' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme Dual Core X190 Build/JRO03C) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Webkit' => '534.30', 'Safari' => '4.0')), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Essential A160 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.3; E-Boda Supreme X80 Dual Core Build/ICS.g12refM806A1YBD.20120925) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; E-boda essential smile Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme X80 Dual Core Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme XL200IPS Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Evolio' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Evolio X7 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ro-ro; ARIA_Mini_wifi Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Fly' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; Fly IQ440; Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; FLY IQ256 Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Fujitsu' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ja-jp; F-10D Build/V21R48A) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'V21R48A', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ru-ru; M532 Build/IML74K) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'IML74K', 'Webkit' => '534.30', 'Safari' => '4.0') ), + + ), + + 'FX2' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; FX2 PAD7 RK Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + ), + + // @ref: http://www.galapad.net/product.html + 'Galapad' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-tw; G1 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Webkit' => '534.30', 'Safari' => '4.0', 'Build' => 'JRO03C') ), + + ), + + 'GoClever' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; el-gr; GOCLEVER TAB A103 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; zh-tw; A7GOCLEVER Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.4; GOCLEVER TAB A104 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; cs-cz; GOCLEVER TAB A93.2 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; sk-sk; GOCLEVER TAB A971 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; lv-lv; GOCLEVER TAB A972BK Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; fr-fr; GOCLEVER TAB A104.2 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; pt-pt; GOCLEVER TAB T76 Build/MID) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'GU' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.0.4; vi-vn; TX-A1301 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'IMM76D', 'Webkit' => '534.30', 'Safari' => '4.0')), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; da-dk; Q702 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'IML74K', 'Webkit' => '534.30', 'Safari' => '4.0')), + + ), + + 'HCL' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; U1 Build/HCL ME Tablet U1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; U1 Build/HCL ME Tablet U1) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; Connect-3G-2.0 Build/HCL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; pt-br; X1 Build/HCL ME Tablet X1) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Hisense' => array( + 'Mozilla/5.0 (Linux; Android 4.4.4; F5281 Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/260.1985.135 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Hudl' => array( + 'Mozilla/5.0 (Linux; Android 4.2.2; Hudl HT7S3 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.82 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + + 'Iconbit' => array( + 'Mozilla/5.0 (Linux; Android 4.1.1; NT-3702M Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36 OPR/16.0.1212.65583' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; NetTAB SPACE II Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'iJoy' => array('Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; Tablet Planet II-v3 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true)), + + 'Intenso' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1.;de-de; INM8002KP Build/JR003H) AppleWebKit/534.30 (KHTML, like Gecko)Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, 'version' => array( + 'Android' => '4.1.1.', 'Webkit' => '534.30', 'Safari' => '4.0' + ), + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; TAB1004 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + ), + + 'INQ' => array( + 'INQ1/R3.9.12 NF-Browser/3.5' => array('isMobile' => true, 'isTablet' => false, 'model' => 'INQ1'), + ), + + // @todo: Test this + 'Intex' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3; en-US; Cloud_X2 Build/MocorDroid4.0.1) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 UCBrowser/9.2.0.419 Mobile' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Cloud Y2 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-in; Cloud X5 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + ), + + 'IRU' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; M702pro Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + ), + + 'JXD' => array('Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; F3000 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true) + ), + + 'Karbonn' => array( + 'Mozilla/5.0 (Linux; Android 4.1.1; ST10 Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + ), + + 'KRAMER' => array( + 'Mozilla/5.0 (Linux; Android 6.0; KT107 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Kobo' => array( + 'Mozilla/5.0 (Linux; U; Android 2.0; en-us;) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 (Kobo Touch)' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '2.0', 'Webkit' => '533.1', 'Safari' => '4.0') ), + ), + + 'Megafon' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.5; ru-ru; MegaFon V9 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; MT7A Build/JRO03C) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31' => array('isMobile' => true, 'isTablet' => true), + ), + + // http://www.mediacomeurope.it/tablet/ + 'Mediacom' => array( + 'Mozilla/5.0 (Linux; Android 6.0.1; M-MPI10C3G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0; M-SP10HXAH Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'MediaTek' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; MT8377 Build/JRO03C) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30/4.05d.1002.m7' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Micromax' => array( + + 'Mozilla/5.0 (Linux; Android 4.1.1; Micromax A110 Build/JRO03C) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.169 Mobile Safari/537.22' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03C', 'Webkit' => '537.22', 'Chrome' => '25.0.1364.169') ), + 'Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; Micromax P250(Funbook) Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Webkit' => '534.30', 'Android' => '4.0', 'Build' => 'IMM76D', 'Safari' => '4.0') ), + + ), + + 'Modecom' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; pl-pl; FreeTAB 1014 IPS X4+ Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'MSI' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.5; el-gr; MSI Enjoy 10 Plus Build/1.2) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + // @ref: https://www.nabitablet.com/ + 'Nabi' => array( + 'Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; NABI-A Build/MASTER) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + 'NEC' => array( + // @ref: http://www.n-keitai.com/n-08d/?from=mediasnet + // @ref: http://devlog.dcm-gate.com/2012/03/medias-tab-n-06duseragnet.html + // @ref: http://keitaiall.jp/N-08D.html aka MEDIAS TAB + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ja-jp; N-08D Build/A5001911) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android AAA; BBB; N-06D Build/CCC) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + + ), + + 'Nexo' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; pl-pl; NEXO 3G Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 ACHEETAHI/2100050074' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Nibiru' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-tw; Nibiru H1 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Nook' => array( + + 'Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; NOOK BNRV200 Build/ERD79 1.4.3) Apple WebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '2.2.1', 'Webkit' => '533.1', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; NOOK BNTV400 Build/ICS) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'ICS', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; Android 4.0.4; BNTV600 Build/IMM76L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36 Hughes-PFB/CID5391275.AID1376709964' => array( 'isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'IMM76L', 'Webkit' => '537.36', 'Chrome' => '28.0.1500.94') ), + + ), + + 'Oneplus' => array( + 'Mozilla/5.0 (Linux; Android 4.3; A0001 Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; xx-xx; A0001 Build/JLS36C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A5000 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; ONEPLUS A5010 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 Mobile Safari/537.36 [FB_IAB/Orca-Android;FBAV/164.0.0.24.95;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A3010) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.185 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 12; KB2003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Odys' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; LOOX Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; LOOX Plus Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.X; de-de; XENO10 Build/ODYS XENO 10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2.2; de-de; ODYS Space Build/I700T_P7_T04_TSCL_FT_R_0_03_1010_110623) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; ODYS-EVO Build/ODYS-EVO) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.X; de-de; Xelio 10 Pro Build/ODYS_Xelio) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; NEO_QUAD10 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.X; de-de; Xelio10Pro Build/ODYS_Xelio) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 2.3.1; en-us; ODYS-Xpress Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; XELIO7PHONETAB Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; XELIO10EXTREME Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; XELIO Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 Mobile UCBrowser/3.2.1.441' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; XELIOPT2 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; nl-nl; ODYS-NOON Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'OverMax' => array( + 'OV-SteelCore(B) Mozilla/5.0 (iPad; CPU OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; pl-pl; OV-SteelCore Build/ICS.g08refem611.20121010) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0.99; Qualcore 1027 4G Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'YONESTablet' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; pl-pl; BC1077 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + // @todo: Research http://www.pantech.com/ + 'Pantech' => array( + 'PANTECH-C790/JAUS08312009 Browser/Obigo/Q05A Profile/MIDP-2.0 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.1; ko-kr; SKY IM-A600S Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; ADR8995 4G Build/GRI40) AppleWebKit/533.1 (KHTML like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 3.2.1; en-us; PantechP4100 Build/HTK75) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array( + 'isMobile' => true, 'isTablet' => true), + ), + + 'Philips' => array( + 'Mozilla/5.0 (Linux; Android 4.0.4; Philips W336 Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.45 Mobile Safari/537.36 OPR/15.0.1162.59192' => array('isMobile' => true, 'isTablet' => false), + 'Philips_T3500/V1 Linux/3.4.5 Android/4.2.2 Release/03.26.2013 Browser/AppleWebKit534.30 Mobile Safari/534.30 MBBMS/2.2 System/Android 4.2.2;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; Philips W3568 Build/Philips_W3568) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; Philips W832 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux;U;Android 4.2.2;es-us;Philips S388 Build/JDQ39) AppleWebkit/534.30 (HTML,like Gecko) Version/4.0 Mobile Safari/534.30;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; Philips W536 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux;U;Android 4.2.2;es-us;Philips S308 Build/JDQ39) AppleWebkit/534.30 (HTML,like Gecko) Version/4.0 Mobile Safari/534.30;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; ru-ru; Philips-W8500 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; ru; Philips W8510 Build/JDQ39) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.8.9.457 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; ru-RU; Philips W3568 Build/Philips W3568) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.1 Mobile Safari/534.30;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; Philips S388 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.1; Build/PI3100.00.00.24) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; W732 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.1; PI7100_93 Build/PI7100.C.00.00.11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'PocketBook' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-ru; PocketBook A10 3G Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + 'PointOfView' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; POV_TAB-PROTAB30-IPS10 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Polaroid' => array( + 'Mozilla/5.0 (Linux; Android 5.1.1; MID4X10 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Praktica' => array( + 'Mozilla/5.0 (Linux; Android 4.0.4; TP750 3GGSM Build/IMM76I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true) + ), + + 'PROSCAN' => array( + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; PLT8088 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03H', 'Webkit' => '534.30', 'Safari' => '4.0') ), + ), + + 'PyleAudio' => array( + 'Mozilla/5.0 (Linux; Android 4.0.4; PTBL92BC Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'IMM76D', 'Webkit' => '537.36', 'Chrome' => '31.0.1650.59')), + + ), + + 'Realme' => array( + 'Mozilla/5.0 (Linux; U; Android 10; en-us; RMX1919 Build/QKQ1.200209.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36 HeyTapBrowser/45.7.1.9' => array('isMobile' => true, 'isTablet' => false), + ), + + 'RockChip' => array( + 'Mozilla/5.0 (Linux; U; Android 2.2.1; hu-hu; RK2818, Build/MASTER) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android Android 2.1-RK2818-1.0.0; zh-cn; MD701 Build/ECLAIR) AppleWebKit/530.17 (KHTML like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => true), + ), + + 'RossMoor' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.1; ru-ru; RM-790 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true) + + ), + + // @ref: http://www.qmobile.com.pk/complete_range.php# + 'QMobile' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; A2 Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + ), + + 'simvalley' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.4; de-de; SP-80 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Skk' => array('Mozilla/5.0 (Linux; U; Android 4.1; en-us; CYCLOPS Build/F10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true)), + + 'Storex' => array( + 'Mozilla/5.0 (Linux; Android 4.1.1; eZee_Tab903 Build/JRO03H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03H', 'Webkit' => '537.36')), + "Mozilla/5.0 (Linux; Android 4.1.1; eZee'Tab785 Build/JRO03C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36" => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03C', 'Webkit' => '537.36')), + "Mozilla/5.0 (Linux; Android 4.0.3; eZee'Tab971 Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19" => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'IML74K', 'Webkit' => '535.19')), + ), + + 'Teclast' => array( + 'Mozilla/5.0 (Linux; Android 4.4.2; P98 3G\xE5\x85\xAB\xE6\xA0\xB8(A3HY) Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'QQ\xe9\x9f\xb3\xe4\xb9\x90HD 4.0.1 (iPad; iPhone OS 8.0; zh_CN)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; A15(E6C2) Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; A10 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; Teclast A10T Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; zh-cn; Teclast P85(A9D3) Build/IMM76D) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; A70H Build/JDQ39) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.8.0.435 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + // http://www.tecno-mobile.com/tablets/product-list/#/ + 'Tecno' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; TECNO P9 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; TECNO DP8D Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.91 Safari/537.36' => array('isMobile' => true, 'isTablet' => true) + ), + + 'Telstra' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-au; T-Hub2 Build/TVA301TELBG3) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + ), + + // @info: http://www.texet.ru/tablet/ + 'texet' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; TM-7021 Build/GB.m1ref.20120116) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '2.3.4', 'Webkit' => '533.1', 'Safari' => '4.0'), 'model' => 'TM-7021' ), + ), + + 'Tolino' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 7 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.2', 'Build' => 'JDQ39', 'Webkit' => '534.30', 'Safari' => '4.0')), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 8.9 Build/JDQ39) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.2', 'Build' => 'JDQ39', 'Webkit' => '534.30', 'Safari' => '4.0')), + 'Mozilla/5.0 (Linux; Android 4.2.2; tolino tab 7 Build/JDQ39) AppleWebkit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36 OPR/18.0.1290.67495' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 7 Build/JDQ39) AppleWebkit/537.36 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Toshiba' => array( + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; TOSHIBA; TSUNAGI)' => array('isMobile' => true, 'isTablet' => false), + // @ref: http://www.toshiba.co.uk/discontinued-products/folio-100/ + 'Mozilla/5.0 (Linux; U; Android 2.2; it-it; TOSHIBA_FOLIO_AND_A Build/TOSHIBA_FOLIO_AND_A) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '2.2', 'Webkit' => '533.1', 'Safari' => '4.0') ), + ), + + 'Trekstor' => array( + 'Mozilla/5.0 (Linux; Android 4.2.2; ST70408-1 Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.2', 'Build' => 'JDQ39', 'Webkit' => '537.31', 'Chrome' => '26.0.1410.58')), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; engb; Build/IMM76D) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3 SurfTab_7.0' => array( + 'isMobile' => true, 'isTablet' => true, + ), + 'Mozilla/5.0 (Linux; Android 4.2.2; VT10416-2 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array( + 'isMobile' => true, 'isTablet' => true + ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; de-de; ST10216-2A Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30;SurfTab_10.1' => array( + 'isMobile' => true, 'isTablet' => true + ), + ), + + 'Tsmine' => array( + 'Mozilla/5.0 (Linux; Android 4.4.2; TM1088 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Ubislate' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; UBISLATE7C+ Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true) + ), + + // https://www.handsetdetection.com/device-detection-database/devices/wevool/ + 'WeVool' => array( + 'Mozilla/5.0 (Linux; Android 5.0; WVT101 Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Visture' => array( + + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; V97 HD Build/LR-97JC) Apple WebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Visture V4 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; Visture V4 HD Build/Visture V4 HD) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; es-es; Visture V5 HD Build/Visture V5 HD) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; Visture V10 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Vivo' => array( + 'Mozilla/5.0 (Linux; Android 11; vivo 1951) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Versus' => array( + 'Mozilla/5.0 (Linux; Android 4.0.4; VS-TOUCHPAD 9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; Versus Touchpad 9.7 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-gb; CnM-TOUCHPAD7 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 BMID/E67A45B1AB' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; CnM TouchPad 7DC Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 TwonkyBeamBrowser/3.3.5-95 (Android 4.1.1; rockchip CnM TouchPad 7DC Build/meizhi_V2.80.wifi8723.20121225.b11c800)' => array('isMobile' => true, 'isTablet' => true), + 'OneBrowser/3.5/Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; TOUCHPAD 7 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; TOUCHTAB Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.1', 'Build' => 'JRO03H', 'Webkit' => '534.30', 'Safari' => '4.0') ), + ), + + + 'Viewsonic' => array( + 'Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; ViewPad 10e Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2; it-it; ViewPad7 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' =>array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2.1; en-ca; ViewSonic VB733 Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.2; en-gb; ViewPad7X Build/HTJ85B) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2; pt-br; ViewPad 10S Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; VB100a Pro Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Vonino' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; Sirius_Evo_QS Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Q8 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + ), + + 'Wolder' => array( + 'Mozilla/5.0 (Linux; Android 4.4; miTab LIVE Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; pt-pt; miTab FUNK Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), + + 'Wolfgang' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.1; nl-nl; AT-AS45q2 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false) + ), + + 'Xoro' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; PAD 9720QR Build/PAD 9719QR) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; PAD720 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => true) + ), + + 'ZTE' => array( + 'Mozilla/5.0 (Linux; U; Android 4.2.1;zh-cn; ZTE V987 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30;' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.5; pt-pt; Blade Build/tejosunhsine) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; ZTE; N880e_Dawoer_Fulllock; China Telecom)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; ZTE; V965W)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; ZTE; Windows Phone - Internet 7; SFR)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; NX549J Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.141 Mobile Safari/537.36 OPR/45.1.2246.125351' => array('isMobile' => true, 'isTablet' => false), + ), + + 'Zync' => array( + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us ; Z909 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1/UCBrowser/8.4.1.204/145/444' => array('isMobile' => true, 'isTablet' => true) + ), + + 'Xiaomi' => array( + 'Mozilla/5.0 (Linux; U; Android 11; zh-cn; Mi 10 Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.116 Mobile Safari/537.36 XiaoMi/MiuiBrowser/15.8.6' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; Redmi 5A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 11; zh-cn; M2012K11C Build/RKQ1.201112.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.116 Mobile Safari/537.36 XiaoMi/MiuiBrowser/15.7.20' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; Redmi Note 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.74 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 11; 21051182G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 11; 21081111RG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 12; M2007J1SC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.48 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ) + +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Prestigio.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Prestigio.php new file mode 100644 index 0000000000..c86e3b192e --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Prestigio.php @@ -0,0 +1,12 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; PMP5297C_QUAD Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; sk-sk; PMP7100D3G Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.4', 'Build' => 'IMM76D', 'Webkit' => '534.30', 'Safari' => '4.0'), 'model' => 'PMP7100D3G' ), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; sk-sk; PMP7280C3G Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 MobilSafari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; PMT3017_WI Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; PMT3037_3G Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; PMT5002_Wi Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; el-gr; PMT5887_3G Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + ), +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Samsung.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Samsung.php new file mode 100644 index 0000000000..83e4d7c1e8 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Samsung.php @@ -0,0 +1,273 @@ + array( + 'MQQBrowser/4.0/Mozilla/5.0 (Linux; U; Android 3.2; zh-cn; GT-P6800 Build/HTJ85B) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true, 'version' => array('MQQBrowser' => '4.0')), + 'SAMSUNG-SGH-P250-ORANGE/P250BVHH8 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Browser/6.2.3.3.c.1.101 (GUI) MMP/2.0' => array('isMobile' => true, 'isTablet' => false), + 'SAMSUNG-GT-B2710/B271MCXKF1 SHP/VPP/R5 Dolfin/2.0 QTV/5.3 SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Dolfin' => '2.0') ), + 'SAMSUNG-SGH-D900i/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Browser/6.2.3.3.c.1.101 (GUI) MMP/2.0' => array('isMobile' => true, 'isTablet' => false), + 'SAMSUNG-GT-S5233T/S5233TXEJE3 SHP/VPP/R5 Jasmine/0.8 Qtv5.3 SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S5380D/S5380FXXKL3; U; Bada/2.0; ru-ru) AppleWebKit/534.20 (KHTML, like Gecko) Dolfin/3.0 Mobile HVGA SMM-MMS/1.2.0 OPN-B' => array('isMobile' => true, 'isTablet' => false), + 'SAMSUNG-GT-C3312/1.0 NetFront/4.2 Profile/MIDP-2.0 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 1.5; de-de; Galaxy Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1' => array('isMobile' => true, 'isTablet' => false), + 'SAMSUNG-GT-S3650/S3650XEII3 SHP/VPP/R5 Jasmine/1.0 Nextreaming SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'JUC (Linux; U; 2.3.6; zh-cn; GT-S5360; 240*320) UCWEB7.9.0.94/140/352' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S5250/S5250XEKJ3; U; Bada/1.0; ru-ru) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.0 Mobile WQVGA SMM-MMS/1.2.0 NexPlayer/3.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; SAMSUNG; SGH-i917)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S8530/S8530XXJKA; U; Bada/1.2; cs-cz) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.2 Mobile WVGA SMM-MMS/1.2.0 OPN-B' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 1.6; ru-ru; Galaxy Build/Donut) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; ru-ru; GT-I5500 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2; en-us; GALAXY_Tab Build/MASTER) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.2; ja-jp; SC-01C Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + // @about FROYO: http://gizmodo.com/5543853/what-is-froyo + 'Mozilla/5.0 (Linux; U; Android 2.2; fr-fr; GT-I9000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; SCH-i909 Build/FROYO) UC AppleWebKit/534.31 (KHTML, like Gecko) Mobile Safari/534.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; ja-jp; SC-01C Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-gb; GT-P1000 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; el-gr; GT-I9001 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-ca; SGH-I896 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; es-us; GT-S5660L Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MicroMessenger/4.5.1.261' => array('isMobile' => true, 'isTablet' => false, 'version' => array('MicroMessenger' => '4.5.1.261')), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-S5660 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S6102 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; pt-br; GT-S5367 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; fr-fr; GT-S5839i Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S7500 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S5830 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; es-us; GT-B5510L Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; pl-pl; GT-I9001-ORANGE/I9001BVKPC Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-I8150 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; nl-nl; GT-I9070 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S5360 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; es-us; GT-S6102B Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; GT-S5830i Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-I8160 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S6802 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; ru-ru; GT-S5830 Build/GRWK74; LeWa_ROM_Cooper_12.09.21) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-N7000 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; GT-P7100 Build/HRI83) AppleWebkit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.2; he-il; GT-P7300 Build/HTJ85B) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 3.2; en-gb; GT-P6200 Build/HTJ85B) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-gb; GT-I9100 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9100G Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; GT-P5100 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build/IML74K) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7' => array( 'isMobile' => true, 'isTablet' => false, 'version' => array('Chrome' => '16.0.912.75') ), + 'Mozilla/5.0 (Linux; Android 4.0.3; SGH-T989 Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Chrome' => '18.0.1025.166') ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P5100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.4; GT-I9300 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; SPH-D710 Build/IMM76I) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; zh-cn; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300-ORANGE/I9300BVBLG2 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; th-th; GT-I9300T Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-I9100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us ; GT-I9100 Build/IMM76D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1/UCBrowser/8.4.1.204/145/355' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-N7000 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; th-th; GT-P6800 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.4; SAMSUNG-SGH-I747 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; es-es; GT-P5110 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.4; GT-P5110 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; zh-cn; SAMSUNG-GT-S7568_TD/1.0 Android/4.0.4 Release/07.15.2012 Browser/AppleWebKit534.30 Build/IMM76D) ApplelWebkit/534.30 (KHTML,like Gecko) Version/4.0 Mobile Safari/534.30' => array( 'isMobile' => true, 'isTablet' => false, 'version' => array('Android' => '4.0.4') ), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P3100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; tr-tr; GT-P3105 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-ca; GT-N8010 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-S7562 Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; GT-N7100 Build/JZO54K) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.123 Mobile Safari/537.22 OPR/14.0.1025.52315' => array( 'isMobile' => true, 'isTablet' => false, 'version' => array( 'Build' => 'JZO54K', 'Webkit' => '537.22', 'Opera' => '14.0.1025.52315' ) ), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-hk; GT-N7105 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; ru-ru; GT-N8000 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.1; SGH-i747M Build/JRO03L) AppleWebKit/535.19(KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Galaxy Nexus - 4.1.1 - with Google Apps - API 16 - 720x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; GT-I8262 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; it-it; Galaxy Nexus Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; SGH-I777 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; GT-S7710 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; GT-I9082 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; SGH-T999L Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; GT-P5210 Build/JDQ39) AppleWebKit/537.36 (KHTML, Like Gecko) Chrome/27.0.1453.90 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; en-us; SAMSUNG GT-I9200 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Version/1.0 Chrome/18.0.1025.308 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.2.2; zh-cn; SCH-I959 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Version/1.0 Chrome/18.0.1025.308 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; nl-nl; SM-T310 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.3; en-us; SAMSUNG SM-P600 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-gb; GT-N5100 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-T530NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-T800 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; fr-fr; SAMSUNG SM-T800 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-T700 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.517 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; CETUS)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; Focus I917 By TC)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; Focus i917)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; FOCUS S)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-I8350)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-i8700)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; GT-S7530)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; Hljchm\'s Wp)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; I917)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; OMNIA 7)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; OMNIA7 By MWP_HS)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; OMNIA7)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; OMNIA7; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i677)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917.)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917R)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i937)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SMG-917R)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG_blocked_blocked_blocked; OMNIA7; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG_blocked_blocked_blocked_blocked; OMNIA7; Orange)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SUMSUNG; OMNIA 7)' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Windows NT 6.2; ARM; Trident/7.0; Touch; rv:11.0; WPDesktop; SAMSUNG; GT-I8750) like Gecko' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.2; ARM; Trident/7.0; Touch; rv:11.0; WPDesktop; GT-I8750) like Gecko' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; en-gb; SAMSUNG GT-I9205 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Version/1.0 Chrome/18.0.1025.308 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; GT-P7510 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; SHV-E160K/VI10.1802 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 5.0.2; SM-T805 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.92 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-T116NQ Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.92 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; SM-G9250 Build/LRX22G; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.121 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/35.0.0.48.273;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-T705Y Build/KOT49H) AppleWebKit/537.36(KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-T705 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.45 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-T533 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-T533 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; SM-T357T Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; SM-T357T Build/LRX22G; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.106 Safari/537.36 [FB_IAB/FB4A;FBAV/66.0.0.33.73;]' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-G9350 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36 MicroMessenger/6.3.13.49_r4080b63.740 NetType/cmnet Language/zh_CN' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; 404SC Build/?buildID?) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-T560 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.109 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-T561 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 2.3.6; en-ph; GT-S5300 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; SANSUNG SM-T555 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'SAMSUNG-GT-C3310R/1.0 NetFront/4.2 Profile/MIDP-2.0 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1; SAMSUNG SM-J120F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T713 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/54.0.2840.68 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T580 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T355Y Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T280 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + // 29 mar 2017 + 'Mozilla/5.0 (Linux; Android 5.0.2; SM-G920F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; SM-N910C Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T817A Build/LMY47X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T670 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SM-T670 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T677A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T677A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SM-T677V Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-P580 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-P580 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T587P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T587P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-P350 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-P350 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (Linux; Android 7.0; SM-G950F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T355Y Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T355Y Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T355Y Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.2 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T355 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-A310F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F/A310FXXU2BQB1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-A310F Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36 [FB_IAB/MESSENGER;FBAV/118.0.0.19.82;]' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F/XXU2BQB6 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1.1; SM-A310F Build/LMY47X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36 BingWeb/6.9.25207603' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A310F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; en-gb; SAMSUNG GT-I9190 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Version/1.0 Chrome/18.0.1025.308 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; GT-I9190 Build/MOB30Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.7.2246.114996' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A510F/A510FXXU4BQD1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T535/T535XXU1BQC1 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500FN/J500FNXXU1BQE2 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0; SAMSUNG SM-N9005/N9005XXSGBQA1 Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G903F/G903FXXU1BQC1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T285 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.5 Chrome/38.0.2125.102 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T585 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T585 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-T585 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; SM-W708YZKAXTC Build/LMY48Z) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; SM-G950F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; SAMSUNG-SM-N900A Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J330F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T830 Build/PPR1.180610.011) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.4349.111 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-T837V Build/M1AJQ) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T720) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/74.0.3729.157 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T510) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/74.0.3729.157 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T387V) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/74.0.3729.157 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // https://github.com/serbanghita/Mobile-Detect/issues/846 + 'Mozilla/5.0 (Linux; Android 10; SM-P610) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; SM-T290) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T515) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/10.1 Chrome/71.0.3578.99 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T590 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36 OPR/53.1.2569.142848' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T590 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T595 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T725 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T817P Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; SM-T817P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-P585N0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.90 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T295) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; SAMSUNG SM-T865) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/11.2 Chrome/75.0.3770.143 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T865) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + // https://github.com/serbanghita/Mobile-Detect/issues/850 + 'Mozilla/5.0 (Linux; Android 11; SM-T970) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 9; SM-A530F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; SM-T860 Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.163 Whale/1.0.0.0 Crosswalk/25.80.14.7 Safari/537.36 NAVER(inapp; search; 710; 10.23.5)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.1; SM-T380) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T380C Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045118 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 9; SM-T380 Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.11 baiduboxapp/11.11.0.12 (Baidu; P1 9)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 9; zh-CN; SM-T380 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.4.0.1020 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SM-T231 Build/KOT49H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Safari/537.36 baiduboxapp/8.6.5 (Baidu; P1 4.4.2)' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; zh-cn; SAMSUNG SM-T231 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 10; SM-T500) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.1.2; SM-G988N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; SM-T536) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 12; SM-G781B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36 EdgA/105.0.1343.50' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; SM-A805N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 9; SM-G965F Build/PPR1.180610.011;) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/106.0.5249.79 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 11; SM-X200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 12; SM-T220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 11; SM-T870) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 12; SM-X906C Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.119 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 12; SM-F916B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 10; SM-F9160 Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/76.0.3809.89 Mobile Safari/537.36 T7/12.4 SP-engine/2.21.0 matrixstyle/0 lite baiduboxapp/5.1.6.10 (Baidu; P1 10) NABar/1.0' => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-F900U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.3396.87 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/16.2 Chrome/92.0.4515.166 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/17.0 Chrome/96.0.4664.104 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 11; SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 11; SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-F916B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/17.0 Chrome/96.0.4664.104 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/17.0 Chrome/96.0.4664.104 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-F926U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/18.0 Chrome/99.0.4844.88 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F916B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.75 Mobile Safari/537.36 ABB/3.0.1" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F916U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.98 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F926B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/104.0.5112.69 Mobile Safari/537.36 EdgW/1.0" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F926B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F926U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.58 Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F926U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 12; SM-F936B Build/SP2A.220305.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/105.0.5195.136 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 9.0; SAMSUNG SM-F900U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + "Mozilla/5.0 (Linux; Android 9.0; SAMSUNG SM-F900U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36" => array('isMobile' => true, 'isTablet' => false), + // Added in https://github.com/serbanghita/Mobile-Detect/issues/912 + "Mozilla/5.0 (Linux; Android 12; SM-X700) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 12; SM-X706B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 12; SM-X900) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 12; SM-X706B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 13; SM-X806B Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/108.0.5359.128 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 13; SM-X706B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 13; SM-X706B Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.130 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + + "Mozilla/5.0 (Linux; Android 12; SM-P613) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 13; SM-P613 Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.58 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + "Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-P613) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/21.0 Chrome/110.0.5481.154 Safari/537.36" => array('isMobile' => true, 'isTablet' => true), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Sony.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Sony.php new file mode 100644 index 0000000000..32919a220f --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Sony.php @@ -0,0 +1,91 @@ + array( + 'SonyEricssonK800i/R1AA Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; es-ar; SonyEricssonE15a Build/2.0.1.A.0.47) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.1-update1; pt-br; SonyEricssonU20a Build/2.1.1.A.0.6) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.3; en-au; SonyEricssonX10i Build/3.0.1.G.0.75) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; ru-ru; SonyEricssonST18i Build/4.0.2.A.0.62) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; hr-hr; SonyEricssonST15i Build/4.0.2.A.0.62) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.4; sk-sk; SonyEricssonLT15i Build/4.0.2.A.0.62) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; th-th; SonyEricssonST27i Build/6.0.B.3.184) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 2.3.7; de-de; SonyEricssonST25i Build/6.0.B.3.184) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; pt-br; Xperia Tablet S Build/TID0092) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.0.3', 'Build' => 'TID0092', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; Android 4.0.3; LT18i Build/4.1.A.0.562) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.3; Sony Tablet S Build/TISU0R0110) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; es-es; Sony Tablet S Build/TISU0143) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; SonyEricssonLT18i Build/4.1.B.0.587) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; fr-ch; SonyEricssonSK17i Build/4.1.B.0.587) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; SonyEricssonLT26i Build/6.1.A.2.45) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; LT22i Build/6.1.B.0.544) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; vi-vn; SonyEricssonLT22i Build/6.1.B.0.544) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; ST23i Build/11.0.A.5.5) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; ST23i Build/11.0.A.2.10) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.0.4; LT28h Build/6.1.E.3.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; SGPT13 Build/TJDS0170) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; ja-jp; SonySO-03E Build/10.1.E.0.265) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.1.2', 'Build' => '10.1.E.0.265', 'Webkit' => '534.30', 'Safari' => '4.0') ), + 'Mozilla/5.0 (Linux; Android 4.1.2; LT26w Build/6.2.B.1.96) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; SGP321 Build/10.3.1.A.0.33) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Android' => '4.2.2', 'Build' => '10.3.1.A.0.33', 'Webkit' => '537.31', 'Chrome' => '26.0.1410.58') ), + 'Mozilla/5.0 (Linux; Android 4.3; C5303 Build/12.1.A.1.205) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; XL39h Build/14.2.A.1.136) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; sv-se; C5503 Build/10.1.1.A.1.273) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; C5502 Build/10.1.1.A.1.310) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; SonyL39t Build/14.1.M.0.202) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; L39u Build/14.1.n.0.63) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-tw; M35c Build/12.0.B.5.37) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.1.2; M35c Build/12.0.B.2.42) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.90 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-CN; M35t Build/12.0.C.2.42) AppleWebKit/534.31 (KHTML, like Gecko) UCBrowser/9.3.2.349 U3/0.8.0 Mobile Safari/534.31' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; D6502 Build/17.1.A.2.69) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; D6503 Build/17.1.A.0.504) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; D6543 Build/17.1.A.2.55) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2004 Build/20.0.A.0.29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-gb; D2005 Build/20.0.A.1.12) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2104 Build/20.0.B.0.84) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2105 Build/20.0.B.0.74) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; pt-br; D2114 Build/20.0.B.0.85) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2302 Build/18.0.B.1.23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; S50h Build/18.0.b.1.23) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.6.3.413 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2303 Build/18.0.C.1.13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2305 Build/18.0.A.1.30) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.138 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D2306 Build/18.0.C.1.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D5303 Build/19.0.1.A.0.207) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; D5306 Build/19.1.A.0.264) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-CN; XM50h Build/19.0.D.0.269) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.7.6.428 U3/0.8.0 Mobile Safari/533.1' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; XM50t Build/19.0.C.2.59) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; D5322 Build/19.0.D.0.253) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; zh-cn; M51w Build/14.2.A.1.146) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.3; M51w Build/14.2.A.1.146) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.136 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.1; D5102 Build/18.2.A.0.9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.1; D5103 Build/18.1.A.0.11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.1; D5106 Build/18.1.A.0.11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.3; en-gb; C6902 Build/14.2.A.1.136) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 GSA/3.2.17.1009776.arm' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; es-es; C6943 Build/14.1.G.2.257) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; C6943 Build/14.3.A.0.681) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.2.2; SGP412 Build/14.1.B.3.320) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; SonySGP321 Build/10.2.C.0.143) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.1.2; SGP351 Build/10.1.1.A.1.307) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.3; SGP341 Build/10.4.B.0.569) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SGP511 Build/17.1.A.2.36) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SGP512 Build/17.1.A.2.36) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; fr-ch; SGP311 Build/10.1.C.0.344) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; SGP312 Build/10.1.C.0.344) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; de-de; SGP521 Build/17.1.A.2.69) AppleWebKit/537.16 (KHTML, like Gecko) Version/4.0 Safari/537.16' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; SGP541 Build/17.1.A.2.36) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.4.2; SGP551 Build/17.1.A.2.72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'SonyEricssonU5i/R2CA; Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 Safari/525' => array('isMobile' => true, 'isTablet' => false), + 'SonyEricssonU5i/R2AA; Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 Safari/525' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/4.0 (PDA; PalmOS/sony/model prmr/Revision:1.1.54 (en)) NetFront/3.0' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Linux mips; U; InettvBrowser/2.2 (00014A;SonyDTV115;0002;0100) KDL40EX720; CC/BEL; en) Presto/2.7.61 Version/11.00' => array('isMobile' => false, 'isTablet' => false), + 'Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; es-ve; SonyST21a2 Build/11.0.A.6.5) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.2; D2533 Build/19.2.A.0.391) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 4.4.4; Xperia SP Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla / 5.0 (Linux; Android 5.0.2; SOT31 Build / 28.0.D.6.71) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 39.0.2171.93 Safari / 537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1.1; E5823 Build/32.0.A.4.11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 5.0; E2303 Build/26.1.A.3.111) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; SGP771 Build/32.4.A.1.54) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 8.0.0; SOV34 Build/41.3.C.0.297; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 6.0.1; 601SO Build/39.0.D.1.25; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.1; F8332 Build/41.2.A.2.223) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/SpecialCases.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/SpecialCases.php new file mode 100644 index 0000000000..142ba06b79 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/SpecialCases.php @@ -0,0 +1,225 @@ + array( + 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; Avant Browser; rv:11.0) like Gecko' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.1; WOW64; Avant TriCore) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 5.1; rv:27.0; Avant TriCore) Gecko/20100101 Firefox/27.0' => array('isMobile' => false, 'isTablet' => false), + ), + 'Console' => array( + + //Nintendo Wii: + 'Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.28 (KHTML, like Gecko) NX/3.0.3.12.14 NintendoBrowser/3.1.1.9577.EU' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/{Version No} NintendoBrowser/{Version No}.US' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7567.US' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7498.US' => array('isMobile' => true, 'isTablet' => false), + //Sony PlayStation: + 'Mozilla/5.0 (PLAYSTATION 3 4.21) AppleWebKit/531.22.8 (KHTML, like Gecko)' => array('isMobile' => false, 'isTablet' => false), + //Microsoft Xbox: + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)' => array('isMobile' => false, 'isTablet' => false), + // WTF? Must investigate. + //'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Xbox)' => array('isMobile' => false, 'isTablet' => false), + + ), + + 'Other' => array( + // Possible conflict with Galapad G1 tablet https://github.com/serbanghita/Mobile-Detect/issues/761 + 'Mozilla/5.0 (Linux; Android 8.0.0; K10 G1 Build/O00623; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; GAAMII G1 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Conflict in registered Model Name(#717) + 'Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; Z999 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.4 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + // Vivaldi Browser + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.148 Safari/537.36 Vivaldi/1.4.589.41' => array('isMobile' => false, 'isTablet' => false), + // Unknown + 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SV1; [eburo v4.0]; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.3; .NET4.0C; .NET4.0E)' => array('isMobile' => false, 'isTablet' => false), + + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + + // @todo 3Q - http://3q-int.com/en/download/tablets7/ + //'Mozilla/5.0 (Linux; U; Android 4.0.4; it-it; MT0729B Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.4; uk-us; RC9716B Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + + // Sogou Explorer (Browser) + //'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 SE 2.X MetaSr 1.0' => null, + //'Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SV1; SE 2.x)' => null, + + 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Iron/37.0.2000.0 Chrome/37.0.2000.0 Safari/537.36' => array('isMobile' => false, 'isTablet' => false, 'version' => array('Iron' => '37.0.2000.0')), + // Liebao Browser + //'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36 LBBROWSER', + 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/32.0.1700.102 Chrome/32.0.1700.102 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0 AlexaToolbar/psPCtGhf-2.2' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (X11; Linux ppc; rv:17.0) Gecko/20130626 Firefox/17.0 Iceweasel/17.0.7' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (X11; Linux) AppleWebKit/535.22+ Midori/0.4' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-us) AppleWebKit/535+ (KHTML, like Gecko) Version/5.0 Safari/535.20+ Midori/0.4' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.20 Safari/537.36 OPR/15.0.1147.18 (Edition Next)' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 5.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0' => array('isMobile' => false, 'isTablet' => false), + 'Opera/9.80 (Windows NT 5.2; WOW64) Presto/2.12.388 Version/12.14' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (X11; FreeBSD amd64; rv:14.0) Gecko/20100101 Firefox/14.0.1' => array('isMobile' => false, 'isTablet' => false), + // @todo Inspect https://gist.githubusercontent.com/pongacm/b7775bebf2b26c09e1f8/raw/0aff83747959386663f3a5c68d7f7150764a8e2d/Varnish%20-%20Tablet%20PC%20(TAB) + // https://github.com/varnish/varnish-devicedetect/issues/19 + 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Tablet PC 2.0; MASMJS)' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MANMJS)' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; MASMJS)' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; Touch; MASMJS)' => array('isMobile' => false, 'isTablet' => false), + 'Opera/9.80 (Windows NT 6.2; WOW64; MRA 8.0 (build 5784)) Presto/2.12.388 Version/12.11' => array('isMobile' => false, 'isTablet' => false), + // IE 10 + 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)' => array('isMobile' => false, 'isTablet' => false), + // IE 11 @todo: Trident(.*)rv.(\d+)\.(\d+) + 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko' => array('isMobile' => false, 'isTablet' => false), + + // TV + 'Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.20.30 ;1.0M ;)' => array('isMobile' => false, 'isTablet' => false), + 'HbbTV/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;)' => array('isMobile' => false, 'isTablet' => false), + 'Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11' => array('isMobile' => false, 'isTablet' => false), + ), + + 'TV' => array( + // @See https://github.com/serbanghita/Mobile-Detect/issues/591 + 'Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 TV Safari/538.1' => array('isMobile' => false, 'isTablet' => false) + //'Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.2.1; en) Presto/2.6.33 Version/10.70' => null + ), + + 'Generic' => array( + + //PaleMoon browser + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:38.9) Gecko/20100101 Goanna/2.0 Firefox/38.9 PaleMoon/26.0.0' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:2.0) Gecko/20100101 Goanna/20160121 PaleMoon/26.0.0' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:38.9) Gecko/20100101 Goanna/2.0 Firefox/38.9 PaleMoon/26.1.1' => array('isMobile' => false, 'isTablet' => false), + + 'Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Tablet; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Sailfish 3.0; Mobile; rv:38.0) Gecko/38.0 Firefox/38.0 SailfishBrowser/1.0' => array('isMobile' => true, 'isTablet' => false, 'version' => array('Sailfish' => '3.0', 'SailfishBrowser' => '1.0', 'Gecko' => '38.0')), + 'Mozilla/5.0 (Linux; U; Sailfish 3.0; Tablet; rv:38.0) Gecko/38.0 Firefox/38.0 SailfishBrowser/1.0' => array('isMobile' => true, 'isTablet' => true, 'version' => array('Sailfish' => '3.0', 'SailfishBrowser' => '1.0', 'Gecko' => '38.0')), + + // Generic Firefox User-agents + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference#Firefox_OS + 'Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Tablet; rv:26.0) Gecko/26.0 Firefox/26.0' => array('isMobile' => true, 'isTablet' => true), + + // Facebook WebView + //'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D201 [FBAN/FBIOS;FBAV/12.1.0.24.20;FBBV/3214247;FBDV/iPhone6,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/7.1.1;FBSS/2; FBCR/AT&T;FBID/phone;FBLC/en_US;FBOP/5]' => null, + + // Outlook + //'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; InfoPath.3; IM-2014-026; IM-2014-043; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14)' => null, + + // Carrefour tablet + 'Mozilla/5.0 (Linux; Android 4.2.2; CT1020W Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.94 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + // @comment: Pipo m6pro tablet + 'Mozilla/5.0 (Linux; Android 4.2.2; M6pro Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + + // https://github.com/varnish/varnish-devicedetect/issues/17 + // To be researched. + 'MobileSafari/9537.53 CFNetwork/672.1.13 Darwin/13.1.0' => array('isMobile' => true, 'isTablet' => false), + 'Appcelerator Titanium/3.2.2.GA (iPod touch/6.1.6; iPhone OS; en_US;)' => array('isMobile' => true, 'isTablet' => false), + + 'Opera Coast/3.0.3.78307 CFNetwork/672.1.15 Darwin/14.0.0' => array('isMobile' => true, 'isTablet' => false), + + 'Mozilla/5.0 (Linux; Android 4.0.3; ALUMIUM10 Build/IML74K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.2.1; en-us; JY-G3 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; hu-hu; M758A Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + + 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; EVOTAB Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Java/1.6.0_22' => array('isMobile' => false, 'isTablet' => false, 'version' => array('Java' => '1.6.0_22') ), + 'Opera/9.80 (Series 60; Opera Mini/6.5.29260/29.3417; U; ru) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Android; Opera Mini/6.5.27452/29.3417; U; ru) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (iPhone; Opera Mini/7.1.32694/27.1407; U; en) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + // New Opera + 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17 OPR/14.0.1025.52315' => array('isMobile' => false, 'isTablet' => false), + // Unknown yet + // Looks like Chromebook + //'Mozilla/5.0 (X11; CrOS armv7l 4920.83.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.103 Safari/537.36' => null, + 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Android 2.3.7; Linux; Opera Mobi/46154) Presto/2.11.355 Version/12.10' => array('isMobile' => true, 'isTablet' => false), + //'Mozilla/5.0 (Linux; U; Android 4.0.3; it-it; DATAM819HD_C Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.3; nl-nl; SGPT12 Build/TID0142) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; cm_tenderloin Build/IMM76L; CyanogenMod-9) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + + //'Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; A210 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, // Acer Iconia Tab + 'Mozilla/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25' => array('isMobile' => true, 'isTablet' => true), + //'Mozilla/5.0 (Linux; U; Android 2.3.6; en-gb; GT-I8150 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => null, + //'Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mercury/7.2 Mobile/10A523 Safari/8536.25' => null, // Mercurio Browser + //'Opera/9.80 (Android 2.3.7; Linux; Opera Tablet/46154) Presto/2.11.355 Version/12.10' => null, + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; sdk Build/MASTER) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => false), // sdk + 'Mozilla/5.0 (Linux; U; Android 4.2; en-us; sdk Build/JB_MR1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), // sdk + + //'Opera/9.80 (X11; Linux zbov) Presto/2.11.355 Version/12.10' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; TOUCHPAD 7 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => null, // 7" Verso Android tablet + //'Mozilla/5.0 (iPhone; U; CPU OS 4_2_1 like Mac OS X) AppleWebKit/532.9 (KHTML, like Gecko) Version/5.0.3 Mobile/8B5097d Safari/6531.22.7' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.3; en-gb; SGPT12 Build/TID0142) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, // sony xperia tablet s unforts + //'Mozilla/5.0 (Linux; U; Android 2.0.6_b1; ru-ru Build/ECLAIR) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17' => null, // PocketBook IQ701 (tablet) + //'Mozilla/5.0 (Linux; Android 4.0.4; z1000 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => null, // It is a tablet with calling + //'Mozilla/5.0 (Linux; Android 4.0.3; cm_tenderloin Build/GWK74) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => null, // HP touch pad running android cyanogenmod + //'Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; Android for Techvision TV1T808 Board Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => null, // My device is tablet but its detected as phone + //'BlackBerry8520/5.0.0.592 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/136' => null, + //'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17' => null, // its a lenovo tablet 2 with windows 8 pro + //'Mozilla/5.0 (Linux; U; Android 3.1; ru-ru; LG-V900 Build/HMJ37) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => null, + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; HTC; Windows Phone 8S by HTC)' => null, + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)' => null, // MS Surface RT tablet actually! + //'Mozilla/5.0 (PLAYSTATION 3 4.11) AppleWebKit/531.22.8 (KHTML, like Gecko)' => null, + //'Mozilla/5.0 (Linux; U; Android 3.2; ru-ru; V9S_V1.4) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => null, // Wrong detection - 7-inch tablet was detected as a phone. Android 3.2.1, native browser + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)' => null, // Nope, its a Microsoft Surface tablet running Windows RT (8) with MSIE 10 + //'Mozilla/5.0 (Linux; U; Android 2.2; es-es; Broncho N701 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => null, // Tablet! + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)' => null, // its a Microsoft surface rt (tablet) + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch; WebView/1.0)' => null, + //'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; Next7P12 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => null, // Nextbook 7SE Tablet + //'Opera/9.80 (X11; Linux zbov) Presto/2.11.355 Version/12.10' => null, // allview alldro speed tablet, android ics, opera mobile + //'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)' => null, // Its a surface in portrait + // Am ramas la pozitia: 207 + + // Android on Windows :) www.socketeq.com + //'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; full Android on Microsoft Windows, pad, pc, n*books Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => null, + + // TV + //'Opera/9.80 (Linux mips; U; InettvBrowser/2.2 (00014A;SonyDTV115;0002;0100) KDL40EX720; CC/BEL; en) Presto/2.7.61 Version/11.00' => null, + + 'Mozilla/5.0 (Android; Mobile; rv:18.0) Gecko/18.0 Firefox/18.0' => array('isMobile' => true, 'isTablet' => false), + // Maxthon + 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.12 (KHTML, like Gecko) Maxthon/3.0 Chrome/18.0.966.0 Safari/535.12' => array('isMobile' => false, 'isTablet' => false), + 'Opera/9.80 (Windows NT 5.1; U; Edition Yx; ru) Presto/2.10.289 Version/12.02' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2; en-us; sdk Build/JB_MR1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows Phone 6.5.3.5)' => array('isMobile' => true, 'isTablet' => false), + 'PalmCentro/v0001 Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PalmSource/Palm-D061; Blazer/4.5) 16;320x320' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Microsoft; XDeviceEmulator)' => array('isMobile' => true, 'isTablet' => false), + // ZTE phone + 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; MAL; N880E; China Telecom)' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Series 60; Opera Mini/7.0.29482/28.2859; U; ru) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (S60; SymbOS; Opera Mobi/SYB-1202242143; U; en-GB) Presto/2.10.254 Version/12.00' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-au; 97D Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Opera/9.80 (Android; Opera Mini/7.0.29952/28.2647; U; ru) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Android; Opera Mini/6.1.25375/28.2555; U; en) Presto/2.8.119 Version/11.10' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Mac OS X; Opera Tablet/35779; U; en) Presto/2.10.254 Version/12.00' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Android; Tablet; rv:10.0.4) Gecko/10.0.4 Firefox/10.0.4 Fennec/10.0.4' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Android; Tablet; rv:18.0) Gecko/18.0 Firefox/18.0' => array('isMobile' => true, 'isTablet' => true), + 'Opera/9.80 (Linux armv7l; Maemo; Opera Mobi/14; U; en) Presto/2.9.201 Version/11.50' => array('isMobile' => true, 'isTablet' => false), + 'Opera/9.80 (Android 2.2.1; Linux; Opera Mobi/ADR-1207201819; U; en) Presto/2.10.254 Version/12.00' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; sdk Build/JRO03E) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; Endeavour 1010 Build/ONDA_MID) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), // Blaupunkt Endeavour 1010 + 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; Tablet-PC-4 Build/ICS.g08refem618.20121102) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + // Tagi tablets + 'Mozilla/5.0 (Linux; U; Android 4.2.2; de-de; Tagi Tab S10 Build/8089) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + ), + + 'Bot' => array( + 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'grub-client-1.5.3; (grub-client-1.5.3; Crawl your own stuff with http://grub.org)' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'Googlebot-Image/1.0' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'Python-urllib/2.5' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'AdsBot-Google (+http://www.google.com/adsbot.html)' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'AdsBot-Google-Mobile (+http://www.google.com/mobile/adsbot.html) Mozilla (iPhone; U; CPU iPhone OS 3 0 like Mac OS X) AppleWebKit (KHTML, like Gecko) Mobile Safari' => array('isMobile' => true, 'isTablet' => false, /*'isBot' => true*/), + 'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko, Google Keyword Suggestion) Chrome/10.0.648.127 Safari/534.16' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'Facebot' => array('isMobile' => false, 'isTablet' => false, /*'isBot' => true*/), + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 (+https://whatis.contentkingapp.com)' => array('isMobile' => false, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.0;) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; AspiegelBot)' => array('isMobile' => true, 'isTablet' => false, /*'isBot' => true*/), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Verizon.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Verizon.php new file mode 100644 index 0000000000..482ae9d111 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Verizon.php @@ -0,0 +1,12 @@ + array( + 'Mozilla/5.0 (Linux; Android 5.1.1; QTAQZ3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; QTAIR7 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 5.1; QTAIR7 Build/LMY47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Safari/537.36 [Pinterest/Android]' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 6.0.1; QTASUN1 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 7.0; QTASUN1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + // Fixes https://github.com/serbanghita/Mobile-Detect/issues/671 + 'Mozilla/5.0(LInux;Android 5.1.1; QTAQTZ3 Build/LMY47V) AppleWebKit/537.36(KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Vodafone.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Vodafone.php new file mode 100644 index 0000000000..eb0f593c81 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/Vodafone.php @@ -0,0 +1,13 @@ + array( + 'Mozilla/5.0 (Linux; U; Android 3.2; hu-hu; SmartTab10-MSM8260-V02d-Dec022011-Vodafone-HU) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; Android 4.0.3; SmartTabII10 Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; SmartTAB 1002 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array('isMobile' => true, 'isTablet' => true), + 'Mozilla/5.0 (Linux; U; Android 4.0.4; de-de, SmartTabII7 Build/A2107A_A404_107_055_130124_VODA) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30' => array( + 'isMobile' => true, 'isTablet' => true, + ), + // https://github.com/serbanghita/Mobile-Detect/issues/780 + 'Mozilla/5.0 (Linux; Android 6.0.1; VFD 1400 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Safari/537.36' => array('isMobile' => true, 'isTablet' => true), + ), +); diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/ZTE.php b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/ZTE.php new file mode 100644 index 0000000000..12a420c971 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/providers/vendors/ZTE.php @@ -0,0 +1,10 @@ + array( + 'Mozilla/5.0 (Linux; Android 4.0.4; V8200plus Build/IMM76I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.166 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; Z999 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.4 Mobile Safari/537.36' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; Z999 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Mobile Safari/537.36 T7/10.11 light/1.0 baiduboxapp/10.11.0.13 (Baidu; P1 7.1.2)' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 7.1.2; Z999 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044403 Mobile Safari/537.36 MMWEBID/8089 MicroMessenger/6.7.3.1360(0x26070339) NetType/WIFI Language/zh_CN' => array('isMobile' => true, 'isTablet' => false), + 'Mozilla/5.0 (Linux; Android 8.1.0; Z999 Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 NewsApp/49.0' => array('isMobile' => true, 'isTablet' => false), + ) +); \ No newline at end of file diff --git a/lib/vendor/mobiledetect/mobiledetectlib/tests/ualist.json b/lib/vendor/mobiledetect/mobiledetectlib/tests/ualist.json new file mode 100644 index 0000000000..b155f5edb2 --- /dev/null +++ b/lib/vendor/mobiledetect/mobiledetectlib/tests/ualist.json @@ -0,0 +1,10510 @@ +{ + "hash": "380861b0aa0ce9d3d1184f2e62efcf726ccefdb9", + "user_agents": [ + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2.1; en-us; A100 Build\/HTK55D) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1; en-us; A110 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; A200 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Webkit": "534.30", + "Safari": "4.0", + "Build": "IML74K" + }, + "model": "A200" + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; A500 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; A501 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; A701 Build\/JRO03H) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; B1-A71 Build\/JZO54K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; B1-710 Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; A1-810 Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Safari\/537.31", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; nl-nl; A1-810 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Acer; Allegro)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; A3-A10 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "JDQ39", + "Webkit": "537.36", + "Chrome": "32.0.1700.99" + } + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; A1-811 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; A1-830 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; A3-A11 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Acer", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; A3-A40 Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/55.0.2883.91 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; en-in; MB525 Build\/GWK74; CyanogenMod-7.2.0) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; it-it; ALCATEL ONE TOUCH 918D Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false, + "version": { + "Android": "2.3.5", + "Webkit": "533.1", + "Safari": "4.0", + "Build": "GRJ90" + }, + "model": "ONE TOUCH 918D" + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; ALCATEL ONE TOUCH 991 Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false, + "version": { + "Android": "2.3.6", + "Webkit": "533.1", + "Safari": "4.0", + "Build": "GRJ90" + }, + "model": "ONE TOUCH 991" + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; ALCATEL ONE TOUCH 993D Build\/ICECREAM) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.0.4", + "Webkit": "534.30", + "Safari": "4.0", + "Build": "ICECREAM" + }, + "model": "ONE TOUCH 993D" + }, + { + "vendor": "Alcatel", + "user_agent": "ALCATEL_A392G\/1.0 ObigoInternetBrowser\/Q05A[TF013513002719521000000013182904148]", + "mobile": true, + "tablet": false, + "model": "A392G" + }, + { + "vendor": "Alcatel", + "user_agent": "ALCATEL_3020D\/1.0 ObigoInternetBrowser\/Q03C", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2; ALCATEL ONE TOUCH 5037A Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "ALCATEL_3020G\/1.0 ObigoInternetBrowser\/Q03C", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "ALCATEL_3041D\/1.0 ObigoInternetBrowser\/Q03C", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 5037E Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 5037X Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 5037X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012A Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-nz; ONE TOUCH 6012A Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012D Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; ONE TOUCH 6012D Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; En-us; ONE TOUCH 6012E Build\/JDQ39) AppleWebKit\/534.30 (KHTML, Like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ONE TOUCH 6012X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.12975 YaBrowser\/13.12.1599.12975 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; bg-bg; ONE TOUCH 6012X Build\/JDQ39) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 6012X_orange Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; fr-fr; ALCATEL ONE TOUCH 6012X_orange Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; fr-fr; 6016E Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; ALCATEL ONE TOUCH 6016E Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; 6016X Build\/JLS36C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; ALCATEL ONE TOUCH 6016X Build\/JLS36C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; ru-ru; 6016X Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 6032A Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.170 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; ru-ru; ALCATEL ONE TOUCH 6032X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-nz; ALCATEL ONE TOUCH 7040A Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; th-th; ALCATEL ONE TOUCH 7040D Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7040D Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7040E Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; it-it; ALCATEL ONE TOUCH 7041D Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7041D Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7041X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; pt-pt; ALCATEL ONE TOUCH 7041X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020A Build\/JDQ39) AppleWebKit\/537.36 (KHTML, Like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020A Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020D Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; es-es; ALCATEL ONE TOUCH 8020D Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020E Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020E Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 8020X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Alcatel", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; ALCATEL ONE TOUCH 8020X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Allview", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; ALLVIEW P5 Build\/IML74K) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Allview", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us ; ALLVIEW SPEEDI Build\/IMM76D) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1\/UCBrowser\/8.5.3.246\/145\/355", + "mobile": true, + "tablet": true + }, + { + "vendor": "Allview", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; AllviewCity Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Allview", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; ALLVIEWSPEED Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; KFTT Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.4 Mobile Safari\/535.19 Silk-Accelerated =true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-US) AppleWebKit\/528.5+ (KHTML, like Gecko, Safari\/528.5+) Version\/4.0 Kindle\/3.0 (screen 600x800; rotate)", + "mobile": true, + "tablet": true, + "version": { + "Webkit": "528.5+", + "Kindle": "3.0", + "Safari": "4.0" + }, + "model": "Kindle" + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; KFOTE Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "IML74K", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; WFJWAE Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-us; KFTT Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.21 Safari\/535.19 Silk-Accelerated=true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-us; KFTHWI Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.21 Safari\/535.19 Silk-Accelerated=true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-us; KFJWI Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.21 Safari\/535.19 Silk-Accelerated=true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-us; KFSOWI Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.21 Safari\/535.19 Silk-Accelerated=true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1; xx-xx; T720-WIFI Build\/ECLAIR) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; KFARWI Build\/LMY47O) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/47.1.79 like Chrome\/47.0.2526.80 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; KFTHWI Build\/KTU84M) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/44.1.54 like Chrome\/44.0.2403.63 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/44.1.54 like Chrome\/44.0.2403.63 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; KFASWI Build\/LMY47O) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/48.2.2 like Chrome\/48.0.2564.95 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; KFFOWI Build\/LMY47O) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/46.1.66 like Chrome\/46.0.2490.80 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; en-us; KFAPWI Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Silk\/3.13 Safari\/535.19 Silk-Accelerated=true", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; KFGIWI Build\/LVY48F) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/56.2.4 like Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amazon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.4; en-us; SD4930UR Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Silk\/3.60 like Chrome\/37.0.2026.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "AOC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; MW0922 Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "AOC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-us; MW0831Plus Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Apple", + "user_agent": "iTunes\/9.1.1", + "mobile": false, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "iTunes\/11.0.2 (Windows; Microsoft Windows 8 x64 Business Edition (Build 9200)) AppleWebKit\/536.27.1", + "mobile": false, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPod touch; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit\/537.51.1 (KHTML, like Gecko) Version\/7.0 Mobile\/11A4449d Safari\/9537.53", + "mobile": true, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit\/420+ (KHTML, like Gecko) Version\/3.0 Mobile\/1A543 Safari\/419.3", + "mobile": true, + "tablet": false, + "version": { + "Webkit": "420+", + "Safari": "3.0" + } + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit\/528.18 (KHTML, like Gecko) Version\/4.0 Mobile\/7A341 Safari\/528.16", + "mobile": true, + "tablet": false, + "version": { + "iOS": "3_0", + "Webkit": "528.18", + "Safari": "4.0" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit\/534.46 (KHTML, like Gecko) Version\/5.1 Mobile\/9B206 Safari\/7534.48.3", + "mobile": true, + "tablet": false, + "version": { + "iOS": "5_1_1", + "Webkit": "534.46", + "Mobile": "9B206", + "Safari": "5.1" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPod; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Version\/6.0 Mobile\/10A403 Safari\/8536.25", + "mobile": true, + "tablet": false, + "version": { + "iOS": "6_0", + "Webkit": "536.26", + "Mobile": "10A403", + "Safari": "6.0" + }, + "model": "iPod" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 5_1_1 like Mac OS X; en-us) AppleWebKit\/534.46.0 (KHTML, like Gecko) CriOS\/21.0.1180.80 Mobile\/9B206 Safari\/7534.48.3 (6FF046A0-1BC4-4E7D-8A9D-6BF17622A123)", + "mobile": true, + "tablet": true, + "version": { + "iOS": "5_1_1", + "Webkit": "534.46.0", + "Chrome": "21.0.1180.80", + "Mobile": "9B206" + }, + "model": "iPad" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Version\/6.0 Mobile\/10A403 Safari\/8536.25", + "mobile": true, + "tablet": true, + "version": { + "iOS": "6_0", + "Webkit": "536.26", + "Safari": "6.0", + "Mobile": "10A403" + }, + "model": "iPad" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit\/533.17.9 (KHTML, like Gecko) Version\/5.0.2 Mobile\/8C148 Safari\/6533.18.5", + "mobile": true, + "tablet": true, + "version": { + "iOS": "4_2_1", + "Webkit": "533.17.9", + "Safari": "5.0.2", + "Mobile": "8C148" + }, + "model": "iPad" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit\/531.21.10 (KHTML, like Gecko) Version\/4.0.4 Mobile\/7B334b Safari\/531.21.10", + "mobile": true, + "tablet": true, + "version": { + "iOS": "3_2", + "Webkit": "531.21.10", + "Safari": "4.0.4", + "Mobile": "7B334b" + }, + "model": "iPad" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X; da-dk) AppleWebKit\/534.46.0 (KHTML, like Gecko) CriOS\/21.0.1180.82 Mobile\/10A523 Safari\/7534.48.3", + "mobile": true, + "tablet": false, + "version": { + "iOS": "6_0_1", + "Webkit": "534.46.0", + "Chrome": "21.0.1180.82", + "Mobile": "10A523" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Version\/6.0 Mobile\/10A523 Safari\/8536.25", + "mobile": true, + "tablet": false, + "version": { + "iOS": "6_0_1", + "Webkit": "536.26", + "Safari": "6.0", + "Mobile": "10A523" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X; ru-ru) AppleWebKit\/536.26 (KHTML, like Gecko) CriOS\/23.0.1271.100 Mobile\/10B142 Safari\/8536.25", + "mobile": true, + "tablet": false, + "version": { + "iOS": "6_1", + "Webkit": "536.26", + "Chrome": "23.0.1271.100", + "Mobile": "10B142" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 6_1_3 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Version\/6.0 Mobile\/10B329 Safari\/8536.25", + "mobile": true, + "tablet": false, + "version": { + "iOS": "6_1_3", + "Webkit": "536.26", + "Safari": "6.0", + "Mobile": "10B329" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Coast\/1.0.2.62956 Mobile\/10B329 Safari\/7534.48.3", + "mobile": true, + "tablet": true, + "version": { + "Coast": "1.0.2.62956" + } + }, + { + "vendor": "Apple", + "user_agent": "CheckMyBus iOS mobile App 0.9.0 (iPhone; iPhone OS\/7.1.1)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit\/537.51.1 (KHTML, like Gecko) Version\/7.0 Mobile\/11A465 Safari\/9537.53", + "mobile": true, + "tablet": true + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit\/600.1.4 (KHTML, like Gecko) CriOS\/38.0.2125.59 Mobile\/12A405 Safari\/600.1.4", + "mobile": true, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 13_4 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) CriOS\/92.0.4515.90 Mobile\/15E148 Safari\/604.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit\/605.1.15 (KHTML, like Gecko) CriOS\/92 Version\/11.1.1 Safari\/605.1.15", + "mobile": false, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "VendorAppName\/1.7.0 (iPhone; iOS 8.1.2; Scale\/3.00)", + "mobile": true, + "tablet": false, + "version": { + "iOS": "8.1.2" + }, + "model": "iPhone" + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 9_0 like Mac OS X) AppleWebKit\/601.1.17 (KHTML, like Gecko) Version\/8.0 Mobile\/13A175 Safari\/600.1.4", + "mobile": true, + "tablet": true + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 9_0 like Mac OS X) AppleWebKit\/601.1.37 (KHTML, like Gecko) Version\/8.0 Mobile\/13A4293g Safari\/600.1.4", + "mobile": true, + "tablet": false + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 9_0_2 like Mac OS X) AppleWebKit\/601.1.46 (KHTML, like Gecko) Version\/9.0 Mobile\/13A452 Safari\/601.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Apple", + "user_agent": "Mozilla\/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Mobile\/15E302 rabbit%2F1.0 baiduboxapp\/0_0.0.3.7_enohpi_4331_057\/1.3.11_2C2%257enohPi\/1099a\/4D6A2107AC77E4AD3E534E146047A21C0EC9262D6OCCBFMJOPA\/1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Archos 97c Platinum Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/52.0.2743.98 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Qilive 97R Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; Archos 50 Platinum Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; fr-fr; A101IT Build\/FROYO) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Archos 101 Neon Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Archos 101 Cobalt Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 80 TITANIUM Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; ARCHOS 101 Titanium Build\/JRO03H) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 70b TITANIUM Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; de-de; Archos 80 Xenon Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Archos 79 Xenon Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 101 Titanium Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 80XSK Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS FAMILYPAD 2 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; ARCHOS 97B TITANIUM Build\/JRO03H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ARCHOS 101 XS 2 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; ARCHOS 80b PLATINUM Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Archos 70 Xenon Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; ARCHOS 97 CARBON Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS 97 TITANIUMHD Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Archos 90 Neon Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 1.6; de-de; Archos5 Build\/Donut) AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Archos", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ARCHOS GAMEPAD Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2.1; en-us; Transformer TF101 Build\/HTK75) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true, + "version": { + "Android": "3.2.1", + "Webkit": "534.13", + "Safari": "4.0" + }, + "model": "Transformer TF101" + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Transformer Build\/JRO03L) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; ASUS Transformer Pad TF300T Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; fr-fr; Transformer Build\/JZO54K; CyanogenMod-10) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; asus_laptop Build\/IMM76L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; PadFone 2 Build\/JRO03L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; PadFone 2 Build\/JRO03L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Build": "JRO03L", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.1; ME301T Build\/JOP40D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.1", + "Build": "JOP40D" + } + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.1; ME173X Build\/JOP40D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.1", + "Build": "JOP40D" + } + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; TF300T Build\/JDQ39E) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "JDQ39E" + } + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; K00C Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; K00E Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; K00F Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; K00L Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ME302KL Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Safari\/537.31", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; K010 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; K017 Build\/KVT49L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; PO1MA build\/LRX21V) AppelWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0(Linus; Android 4.4.2; K011 Build\/KOT49H)AppleWebKit\/537.36 (KHTML, like Gecko)Chrome\/53.0.2785.124 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; K01E Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; P01Z Build\/LRX22G; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; P027 Build\/MRA58L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; P024 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/61.0.3163.100 YaBrowser\/17.10.2.145.01 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; P024 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; P00C Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; ASUS_Z01QD) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.185 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; K01A Build\/JSS15Q) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "ASUS", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; ASUS_X00TD; Flow) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/359.0.0.288 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit\/534.8+ (KHTML, like Gecko) Version\/6.0.0.546 Mobile Safari\/534.8+", + "mobile": true, + "tablet": false, + "version": { + "Webkit": "534.8+", + "BlackBerry": "6.0.0.546" + }, + "model": "BlackBerry 9300" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9360; en-US) AppleWebKit\/534.11+ (KHTML, like Gecko) Version\/7.0.0.400 Mobile Safari\/534.11+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9700; he) AppleWebKit\/534.8+ (KHTML, like Gecko) Version\/6.0.0.723 Mobile Safari\/534.8+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit\/534.8 (KHTML, like Gecko) Version\/6.0.0.448 Mobile Safari\/534.8", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9790; en-GB) AppleWebKit\/534.11+ (KHTML, like Gecko) Version\/7.1.0.714 Mobile Safari\/534.11+", + "mobile": true, + "tablet": false, + "version": { + "Webkit": "534.11+", + "BlackBerry": "7.1.0.714" + }, + "model": "BlackBerry 9790" + }, + { + "vendor": "BlackBerry", + "user_agent": "Opera\/9.80 (BlackBerry; Opera Mini\/7.0.29990\/28.2504; U; en) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9981; en-GB) AppleWebKit\/534.11+ (KHTML, like Gecko) Version\/7.1.0.342 Mobile Safari\/534.11+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit\/534.8+ (KHTML, like Gecko) Version\/6.0.0.546 Mobile Safari\/534.8+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9780; es) AppleWebKit\/534.8 (KHTML, like Gecko) Version\/6.0.0.480 Mobile Safari\/534.8", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9810; en-US) AppleWebKit\/534.11 (KHTML, like Gecko) Version\/7.0.0.583 Mobile Safari\/534.11", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9860; es) AppleWebKit\/534.11+ (KHTML, like Gecko) Version\/7.0.0.576 Mobile Safari\/534.11+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit\/534.11 (KHTML, like Gecko) Version\/7.1.0.523 Mobile Safari\/534.11", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "BlackBerry8520\/5.0.0.592 Profile\/MIDP-2.1 Configuration\/CLDC-1.1 VendorID\/136", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "BlackBerry8520\/5.0.0.1067 Profile\/MIDP-2.1 Configuration\/CLDC-1.1 VendorID\/603", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "BlackBerry8520\/5.0.0.1036 Profile\/MIDP-2.1 Configuration\/CLDC-1.1 VendorID\/611", + "mobile": true, + "tablet": false, + "version": { + "BlackBerry": "5.0.0.1036", + "VendorID": "611" + }, + "model": "BlackBerry8520" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BlackBerry; U; BlackBerry 9220; en) AppleWebKit\/534.11+ (KHTML, like Gecko) Version\/7.1.0.337 Mobile Safari\/534.11+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit\/536.2+ (KHTML, like Gecko) Version\/7.2.1.0 Safari\/536.2+", + "mobile": true, + "tablet": true + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BB10; Touch) AppleWebKit\/537.1+ (KHTML, like Gecko) Version\/10.0.0.1337 Mobile Safari\/537.1+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BB10; Touch) AppleWebKit\/537.10+ (KHTML, like Gecko) Version\/10.0.9.2372 Mobile Safari\/537.10+", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (BB10; Touch) \/537.10+ (KHTML, like Gecko) Version\/10.0.9.2372 Mobile Safari\/537.10+", + "mobile": true, + "tablet": false, + "version": { + "BlackBerry": "10.0.9.2372" + } + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2.1; en-us; Transformer TF101 Build\/HTK75) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true, + "version": { + "Android": "3.2.1", + "Webkit": "534.13", + "Safari": "4.0" + }, + "model": "Transformer TF101" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; A200 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "A200" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; A500 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "A500" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; A501 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "A501" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Transformer Build\/JRO03L) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Webkit": "535.19", + "Chrome": "18.0.1025.166" + }, + "model": "Transformer" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; ASUS Transformer Pad TF300T Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Webkit": "535.19", + "Chrome": "18.0.1025.166" + }, + "model": "Transformer Pad TF300T" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; fr-fr; Transformer Build\/JZO54K; CyanogenMod-10) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.2", + "Webkit": "534.30", + "Safari": "4.0", + "Build": "JZO54K" + }, + "model": "Transformer" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; B1-A71 Build\/JZO54K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.2", + "Webkit": "535.19", + "Chrome": "18.0.1025.166" + }, + "model": "B1-A71" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Acer; Allegro)", + "mobile": true, + "tablet": false, + "version": { + "Windows Phone OS": "7.5", + "Trident": "5.0", + "IE": "9.0" + }, + "model": "Allegro" + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; BBA100-1 Build\/6.0.1_0.223.0.064) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; BBB100-1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/76.0.3809.89 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; BBB100-3 Build\/NMF26F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1; BBD100-1 Build\/N2G47H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/62.0.3202.84 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; BBE100-1 Build\/OPM1.171019.026) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/69.0.3497 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; BBF100-9 Build\/OPM1.171019.026) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/67.0.3396.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "BlackBerry", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; STH100-1 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/55.0.2883.91 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 1.6; en-gb; Dell Streak Build\/Donut AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/ 525.20.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; hd-us; Dell Venue Build\/GWK74; CyanogenMod-7.2.0) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; DELL; Venue Pro)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Venue 8 3830 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Venue 7 3730 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Venue 7 HSPA+ Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; Venue 8 3830 Build\/JSS15Q) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; zh-cn; Dell Streak 10 Pro Build\/HTJ85B) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Dell", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 7.0.1; en-US; Dell Streak 7 Build\/FRF91) AppleWebKit\/51.0 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/51.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Nexus 4 Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.40 Mobile Safari\/537.31 OPR\/14.0.1074.54070", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.2.2", + "Build": "JDQ39", + "Webkit": "537.31", + "Opera": "14.0.1074.54070" + } + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Nexus 4 Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.2.2", + "Chrome": "26.0.1410.58" + } + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build\/JRO03S) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; Google Galaxy Nexus - 4.1.1 - API 16 - 720x1280 Build\/JRO03S) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Nexus 7 Build\/JRO03D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2; Nexus 7 Build\/JOP40C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; Nexus 7 Build\/JZ054K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.2", + "Chrome": "18.0.1025.166" + } + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; cs-cz; Nexus S Build\/JZO54K; CyanogenMod-10.0.0) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; Nexus 10 Build\/JWR66Y) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; U; Android; en_us; Nexus 7 Build\/) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 NetFrontLifeBrowser\/2.3 Mobile (Dragonfruit)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; Nexus 5 Build\/LMY47D) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/39.0.0.0 Mobile Safari\/537.36 momoWebView\/6.3.1 android\/404(Nexus 5;android 5.1;zh_CN;10;netType\/1)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/106.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; Nexus 10 Build\/JWR66Y) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1; Pixel XL Build\/NDE63H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1; Pixel Build\/NDE63H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Pixel C Build\/OPM1.171019.011; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/65.0.3325.109 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Pixel C Build\/OPM1.171019.026) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Google", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Pixel 2 Build\/OPM2.171026.006.G1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/67.0.3396.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (hp-tablet; Linux; hpwOS\/3.0.5; U; en-GB) AppleWebKit\/534.6 (KHTML, like Gecko) wOSBrowser\/234.83 Safari\/534.6 TouchPad\/1.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; HP Slate 7 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HP Slate 7 Build\/JRO03H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; HP 8 Build\/1.0.7_WW-FIR-13) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HP Slate 10 HD Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HP Slate 8 Pro Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Slate 21 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Safari\/537.36 OPR\/22.0.1485.78487", + "mobile": true, + "tablet": true + }, + { + "vendor": "HP", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HP SlateBook 10 x2 PC Build\/4.3-17r20-03-23) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (X11; Linux x86_64; Z520m; en-ca) AppleWebKit\/534.24 (KHTML, like Gecko) Chrome\/11.0.696.34 Safari\/534.24", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "HTC_Touch_HD_T8282 Mozilla\/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 1.5; en-us; ADR6200 Build\/CUPCAKE) AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1; xx-xx; Desire_A8181 Build\/ERE27) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build\/ERE27) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; en-gb; HTC Desire Build\/ERE27) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; fr-fr; HTC Desire Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; en-dk; Desire_A8181 Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; xx-xx; 001HT Build\/FRF91) AppleWebKit\/525.10+ (KHTML, like Gecko) Version\/3.0.4 Mobile Safari\/523.12.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; xx-xx; HTCA8180\/1.0 Android\/2.2 release\/06.23.2010 Browser\/WAP 2.0 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.2; de-at; HTC Desire Build\/FRG83G) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.2; en-sk; Desire_A8181 Build\/FRG83G) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3; xx-xx; HTC\/DesireS\/1.07.163.1 Build\/GRH78C) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-lv; HTC_DesireZ_A7272 Build\/GRI40) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; en-us; ADR6300 Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; en-gb; HTC\/DesireS\/2.10.161.3 Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC_DesireS_S510e Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; en-us; Inspire 4G Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; de-de; HTC Explorer A310e Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; en-gb; HTC_ChaCha_A810e Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; nl-nl; HTC_DesireHD_A9191 Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; ru-ru; HTC Desire S Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-au; HTC Desire Build\/GRI40) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; de-de; HTC_DesireHD Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; ru-ua; HTC_WildfireS_A510e Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; en-us; HTC Vision Build\/GRI40; ILWT-CM7) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0; xx-xx; HTC_GOF_U\/1.05.161.1 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; hu-hu; HTC Sensation Z710e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC Sensation XE with Beats Audio Z715e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; pl-pl; EVO3D_X515m Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC_One_S Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru-ru; HTC_One_V Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC_A320e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; zh-tw; HTC Desire V Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; PG86100 Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-nl; SensationXE_Beats_Z715e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; ADR6425LVW 4G Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; cs-ee; Sensation_Z710e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; HTC Evo 4G Build\/MIUI) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; Desire HD Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-my; HTC_One_X Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; it-it; IncredibleS_S710e Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; fr-fr; HTC_Desire_S Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC Butterfly Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; EVO Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTCSensation Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; GT-S6312 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC 7 Mozart T8698; QSD8x50)", + "mobile": true, + "tablet": false, + "version": { + "IE": "9.0", + "Windows Phone OS": "7.5", + "Trident": "5.0" + }, + "model": "7 Mozart T8698" + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2.1; en-gb;HTC_Flyer_P512 Build\/HTK75C) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.1; zh-tw; HTC PG09410 Build\/HMJ15) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 HTC MOZART)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Mondrian T8788)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Mozart T8698)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Mozart)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Mozart; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Pro T7576)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Pro)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Schubert T9292)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Surround)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Trophy T8686)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; 7 Trophy)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Eternity)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Gold)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; HD2 LEO)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; HD2)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; HD7 T9292)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; HD7)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; iPad 3)", + "mobile": true, + "tablet": true + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; LEO)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Mazaa)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Mondrian)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Mozart T8698)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Mozart)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; mwp6985)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; PC40100)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; PC40200)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; PD67100)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; PI39100)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; PI86100)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar 4G)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar C110e)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar C110e; 1.08.164.02)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar C110e; 2.05.164.01)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar C110e; 2.05.168.02)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Radar; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Schuber)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Schubert T9292)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Schubert)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Spark)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Surround)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; T7575)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; T8697)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; T8788)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; T9295)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; T9296)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; TITAN X310e)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Titan)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; Torphy T8686)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC; X310e)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; HTC_blocked; T8788)", + "mobile": true, + "tablet": false, + "version": { + "IE": "9.0", + "Windows Phone OS": "7.5", + "Trident": "5.0" + }, + "model": "T8788" + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; HTC One S Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; de-de; HTC One X Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-th; HTC One V Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; HTC One X Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-id; HTC One X Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One S Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One X Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-at; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03L) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.123 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.123 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One X Build\/JZO54K) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; es-pe; HTC One V Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; HTC One X Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 Maxthon\/4.0.4.1000", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One X Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.133 Mobile Safari\/535.19 AlexaToolbar\/alxf-2.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One S Build\/IML74K) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; de-de; HTC One Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31 OPR\/14.0.1074.58201", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-es; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.64 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.64 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.64 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39E) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One XL Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.63 Mobile Safari\/537.36 OPR\/15.0.1162.60140", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One X Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.24 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "HTC One X Linux\/3.0.13 Android\/4.1.9 Release\/10.12.2012 Browser\/AppleWebKit534.30 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 Mobile Safari\/534.30 Android 4.0.1;", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One 801e Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; HTC One X Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.63 Mobile Safari\/537.36 OPR\/15.0.1162.61541", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One XL Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X+ Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; HTC One X Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30\/4.05d.1002.m7", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-in; HTC One V Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC One X Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 MicroMessenger\/5.0.1.352", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; HTC One X Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; HTC One Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One SV Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One mini Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; HTC One Build\/IMM76D) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One 801e Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-ch; HTC One Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; nl-nl; HTC One X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; zh-cn; HTC One S Build\/IML74K) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17 T5\/2.0 baidubrowser\/3.1.6.4 (Baidu; P1 4.0.3)", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X+ Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; HTC One 801e Build\/JSS15J) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.4.1.362 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4; HTC One Build\/KRT16S.H5) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One SV Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.1; ru-ru; HTC One Build\/JOP40D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; ru-ru; HTC One 801e Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One 801e Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One mini Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.12975 YaBrowser\/13.12.1599.12975 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4; HTC One Build\/KRT16S) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; HTC One Build\/JSS15J) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One X Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One X Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JWR66Y.H1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; de-at; HTC One Build\/JSS15J) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X+ Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One dual sim Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; HTC One S Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One max Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One mini Build\/JSS15Q) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One 801e Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-cn; HTC One Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 MicroMessenger\/5.2.380", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One X Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.133 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X+ Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; HTC One X Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; it-it; HTC One S Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-kw; HTC One X+ Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One max Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 MicroMessenger\/5.3.0.49_r693790.420", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru; HTC One V Build\/IML74K) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.7.5.418 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 MicroMessenger\/5.2.1.381", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One mini Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; ru-ru; HTC One mini Build\/KOT49H) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru; HTC One V Build\/IML74K) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.8.0.435 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One 801e Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; HTC One X - 4.2.2 - API 17 - 720x1280 Build\/JDQ39E) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X+ Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.128 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.128 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.128 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One_M8 Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; HTC One VX Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.76 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One V Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One dual sim Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One dual sim Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36 OPR\/22.0.1485.78487", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X+ Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One_M8 Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One 801e Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One 801e Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; HTC One X Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36 OPR\/22.0.1485.81203", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One 801e Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; HTC One S Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-tw; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One_M8 Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; HTC One V Build\/IML74K) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.9.2.467 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One mini Build\/JSS15Q) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; en-us; HTC One_M8 Build\/KOT49H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One dual sim Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/37.0.2062.117 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.72 Mobile Safari\/537.36 OPR\/19.0.1340.69721", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One_M8 Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One SV Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 ACHEETAHI\/2100050056", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One_M8 Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JWR66Y.H1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One SV Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 [FBAN\/FB4A;FBAV\/21.0.0.23.12;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-tw; HTC One X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; ru-si; HTC One X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 MicroMessenger\/6.0.0.67_r853700.483 NetType\/WIFI", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 [FBAN\/FB4A;FBAV\/22.0.0.15.13;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-US; HTC One X Build\/JRO03C) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/10.0.1.512 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One Build\/KTU84P.H1) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 [FBAN\/FB4A;FBAV\/22.0.0.15.13;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 [FBAN\/FB4A;FBAV\/22.0.0.15.13;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One SV Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 [FBAN\/FB4A;FBAV\/22.0.0.15.13;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-tw; HTC One X+ Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 BingWeb\/5.2.0.20140710", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; HTC One Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-mx; HTC One S Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 [FBAN\/FB4A;FBAV\/23.0.0.22.14;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.3; es-es; HTC One 801e Build\/KTU84L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X+ Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.69 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; HTC One S Build\/JRO03C) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; en-th; HTC One Build\/KOT49H) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; es-ar; HTC One X Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One_M8 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-us; HTC One X+ Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; es-mx; HTC One S Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/24.0.0.30.15;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; HTC One Build\/KTU84L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.89 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One dual sim Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.89 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/25.0.0.19.30;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.1; HTC One_M8 Build\/LRX22C) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/37.0.0.0 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/25.0.0.19.30;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.89 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; HTC One_M8 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.109 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; HTC One X Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; HTC One mini Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.109 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.1; HTC One_M8 Build\/LRX22C.H5) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.109 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; Pixel Build\/OPR6.170623.012) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.125 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "HTC", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1; Pixel XL Build\/NDE63H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.162 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; Pixel XL Build\/PQ3A.190801.002; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.149 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/263.0.0.46.121;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Pixel XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/83.0.4103.96 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; PIXEL 2 XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.162 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 2 XL Build\/QQ2A.200305.002; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.132 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/262.0.0.34.117;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build\/OPD1.170816.004) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/77.0.9805.620 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 2 Build\/QQ1A.191205.008; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.149 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/261.0.0.52.126;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Pixel C Build\/OPM8.190405.001; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.132 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel Build\/QP1A.191005.007.A3; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.132 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/261.0.0.52.126;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 3 Build\/QQ2A.200305.002; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.149 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/263.0.0.46.121;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 3) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.162 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 3a) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.149 Mobile Safari\/537.36 OPR\/57.1.2830.52480", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 3a XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; Pixel 3 XL Build\/PQ3A.190801.002; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/76.0.3809.89 Mobile Safari\/537.36 T7\/11.21 SP-engine\/2.17.0 baiduboxapp\/11.21.0.10 (Baidu; P1 9)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Pixel 4 XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pixel", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; Pixel 4a) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/87.0.4280.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; bg-bg; Ideos S7 Build\/ERE27) AppleWebKit\/525.10+ (KHTML, like Gecko) Version\/3.0.4 Mobile Safari\/523.12.2", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1; en-us; Ideos S7 Build\/ERE27) AppleWebKit\/525.10+ (KHTML, like Gecko) Version\/3.0.4 Mobile Safari\/523.12.2", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; lt-lt; U8660 Build\/HuaweiU8660) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; ru-ru; HUAWEI-U8850 Build\/HuaweiU8850) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; pl-pl; MediaPad Build\/HuaweiMediaPad) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; nl-nl; HUAWEI MediaPad Build\/HuaweiMediaPad) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "HUAWEI_T8951_TD\/1.0 Android\/4.0.4 (Linux; U; Android 4.0.4; zh-cn) Release\/05.31.2012 Browser\/WAP2.0 (AppleWebKit\/534.30) Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; ar-eg; MediaPad 7 Youth Build\/HuaweiMediaPad) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; zh-cn; HW-HUAWEI_C8815\/C8815V100R001C541B135; 540*960; CTC\/2.0) AppleWebKit\/534.30 (KHTML, like Gecko) Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-cn; HW-HUAWEI_C8813D\/C8813DV100R001C92B172; 480*854; CTC\/2.0) AppleWebKit\/534.30 (KHTML, like Gecko) Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-cn; HW-HUAWEI_Y300C\/Y300CV100R001C92B168; 480*800; CTC\/2.0) AppleWebKit\/534.30 (KHTML, like Gecko) Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; id-id; HUAWEI Y330-U11 Build\/HuaweiY330-U11) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16 Chrome\/33.0.0.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; HUAWEI M2-A01L Build\/HUAWEIM2-A01L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/59.0.3071.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; HUAWEI GRA-L09 Build\/HUAWEIGRA-L09) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/63.0.3239.111 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; FRD-L09 Build\/HUAWEIFRD-L09) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/63.0.3239.111 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0; DUK-AL20 Build\/HUAWEIDUK-AL20; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.132 MQQBrowser\/6.2 TBS\/044054 Mobile Safari\/537.36 V1_AND_SQ_7.5.8_818_YYB_D QQ\/7.5.8.3490 NetType\/WIFI WebP\/0.3.0 Pixe", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; BAH-L09 Build\/HUAWEIBAH-L09) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; BAH-W09 Build\/HUAWEIBAH-W09) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/62.0.3202.84 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; WAS-LX3 Build\/HUAWEIWAS-LX3; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/63.0.3239.111 Mobile Safari\/537.36 [FB_IAB\/Orca-Android;FBAV\/162.0.0.19.90;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Nexus 6P Build\/OPM3.171019.014) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/64.0.3282.137 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; CMR-AL19 Build\/HUAWEICMR-AL19) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/68.0.3440.70 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; AGS-L09 Build\/HUAWEIAGS-L09; xx-xx) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/59.0.3071.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; EDI-AL10 Build\/HUAWEIEDISON-AL10; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/72.0.3626.121 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; cs-cz; HUAWEI G510-0200 Build\/HuaweiG510-0200) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; KOB2-L09) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/92.0.4515.166 Safari\/537.36 OPR\/65.1.3381.61266", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; BG2-U03) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/87.0.4280.101 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Huwaei", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; BG2-W09 Build\/HuaweiBAGGIO2; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/55.0.2883.91 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; Iris 349 Build\/MocorDroid2.3.5) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; iris402+ Build\/iris402+) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; IRIS402 Build\/LAVAIRIS402) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; iris405 Build\/LAVAIRIS405) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; IRIS_501 Build\/LAVAIRIS501) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; iris402e Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; iris503e Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "UCWEB\/2.0 (Linux; U; Opera Mini\/7.1.32052\/30.3697; en-US; IRIS402) U2\/1.0.0 UCBrowser\/9.1.1.420 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "UCWEB\/2.0 (MIDP-2.0; U; Adr 4.2.2; en-US; IRIS402) U2\/1.0.0 UCBrowser\/9.1.1.420 U2\/1.0.0 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "UCWEB\/2.0 (Linux; U; Opera Mini\/7.1.32052\/30.3697; en-US; IRIS355) U2\/1.0.0 UCBrowser\/9.1.1.420 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; iris356 Build\/irisIRIS356) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.5.0.360 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "UCWEB\/2.0 (Linux; U; Opera Mini\/7.1.32052\/30.3697; en-US; iris356) U2\/1.0.0 UCBrowser\/9.0.2.389 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; iris500 Build\/iris500) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; iris700 Build\/iris700) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; QPAD E704 Build\/JDQ39) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/36.0.1985.131 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2; xx-xx; IvoryS Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-US; E-TAB IVORY Build\/E702) AppleWebKit\/534.31 (KHTML, like Gecko) UCBrowser\/9.3.0.321 U3\/0.8.0 Mobile Safari\/534.31", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lava", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; tr-tr; E-TAB Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": 0, + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-au; TBLT10Q-32GB Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-es; IdeaTab_A1107 Build\/MR1) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; IdeaTab A2107A-H Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-au; ThinkPad Tablet Build\/ThinkPadTablet_A400_03) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "UCWEB\/2.0 (Linux; U; Opera Mini\/7.1.32052\/30.3697; en-US; IdeaTabA1000-G) U2\/1.0.0 UCBrowser\/9.2.0.419 Mobile", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; IdeaTabA1000-F Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.1; Lenovo A3000-H Build\/JOP40D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.117 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; IdeaTab A3000-F Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.360", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1; zh-cn; Lenovo-A3000-H\/S100) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.1 Mobile Safari\/534.300", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; es-us; IdeaTab A3000-F Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; IdeaTab A2107A-H Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; IdeaTab A2107A-H Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-es; IdeaTabA2109A Build\/JRO03R) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; nl-nl; IdeaTabA2109A Build\/JRO03R) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-es; IdeaTab_A1107 Build\/MR1) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.300", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; IdeaTab S6000-H Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; IdeaTab S6000-F Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Lenovo B8000-F Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2;it-it; Lenovo B8000-F\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; it-it; Lenovo B6000-F\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.2.2 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Lenovo B6000-F Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; IdeaPadA10 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; Ideapad K1 Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; de-de; IdeaPad A1 Build\/GRK393; CyanogenMod-7) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; Lenovo B8080-H Build\/JLS36C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; hu-hu; Lenovo A3500-FL Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; Lenovo A7600-F Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Lenovo A5500-F Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.131 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Lenovo A390 Linux\/3.0.13 Android\/4.4.2 Release\/04.03.2013 Browser\/AppleWebKit534.30 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 Mobile Safari\/534.30 Android 4.0.1;", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Lenovo TAB 2 A7-30F Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/45.0.2454.84 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Lenovo A319 Build\/MocorDroid4.4.2) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/48.0.2564.95 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; Lenovo YT3-X90L Build\/LMY47I) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/49.0.2623.105 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo TB-X103F Build\/LenovoTB-X103F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-X304F Build\/NMF26F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/60.0.3112.116 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo TB-8703F Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; Lenovo P2a42 Build\/NRD90N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo P2a42 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-X304L Build\/NMF26F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Tab2A7-10F Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36 ACHEETAHI\/1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo TB2-X30L Build\/LenovoTB2-X30L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/65.0.3325.109 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0(Linux;Android 6.0.1;Lenovo YT3-X50L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.80 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30F Build\/LenovoTB2-X30F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/67.0.3396.81 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30F Build\/LenovoTB2-X30F; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/43.0.2357.121 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; Lenovo TB2-X30M_PRC_YZ_A Build\/LenovoTB2-X30M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/10.4 light\/1.0 baiduboxapp\/10.4.5.11 (Baidu; P1 5.1.1)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.1(Linux; U; Android 5.0; zh-cn; Lenovo YT3-X50M Build\/LMY47V) AppleWebKit\/537.36(KHTML, like Gecko) Version\/4.0 Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo YT3-X50F Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.154 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Tab2A7-20F Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36 hsp", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Lenovo A5500-HV Build\/JDQ39; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/7.9 baiduboxapp\/9.0.0.10 (Baidu; P1 4.2.2)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; zh-cn; LNV-Lenovo A5500\/A5500_S165_161206; 1280x720; CTC\/2.0) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/37.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo YT-X703F Build\/S100) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/69.0.3497.100 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo YT-X703L Build\/S100; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/58.0.3029.83 Safari\/537.36 clicash_android v=1.671", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Lenovo TB-8703N Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.154 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-8704N Build\/NMF26F; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/10.6 baiduboxapp\/10.6.5.10 (Baidu; P1 7.1.1)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-8704F Build\/NMF26F; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/10.5 baiduboxapp\/10.5.5.10 (Baidu; P1 7.1.1)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Lenovo TB3-730M Build\/MRA58K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/46.0.2490.76 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Lenovo TB3-730F Build\/MRA58K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/10.7 baiduboxapp\/10.7.5.10 (Baidu; P1 6.0)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Lenovo TB3-730X Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/65.0.3325.109 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-X704F Build\/NMF26F; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/52.0.2743.100 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Lenovo TB-X104F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/81.0.4044.138 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Lenovo TB3-X70F Build\/MRA58K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 T7\/10.3 baiduboxapp\/10.3.6.13 (Baidu; P1 6.0)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 6.0; zh-CN; Lenovo TB3-X70F Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.108 UCBrowser\/11.9.4.974 UWS\/2.13.2.100 Mobile Safari\/537.36 AliApp(DingTalk\/5.0.5) com.alibaba.android.rimet\/1272", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; Lenovo TB-X705F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/85.0.4183.81 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-8504F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/81.0.4044.138 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F Build\/LRX21M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2490.76 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/76.0.3809.132 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Lenovo TB-X704L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.132 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; Lenovo TB-J606F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/94.0.4606.85 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Lenovo TB-X606F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/97.0.4692.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Lenovo TB-X306X) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/95.0.4638.74 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Lenovo", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; Lenovo YT-J706X) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/106.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; LG-VS410PP Build\/GRK39F) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; en-us; LG-P509 Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 MMS\/LG-Android-MMS-V1.0\/1.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.2; pt-br; LG-P350f Build\/FRG83G) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 MMS\/LG-Android-MMS-V1.0\/1.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-us; LG-P500 Build\/GRI40) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 MMS\/LG-Android-MMS-V1.0\/1.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-us; LS670 Build\/GRI40) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; ru-ru; LG-E510 Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 MMS\/LG-Android-MMS-V1.0\/1.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; en-us; VS910 4G Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; nl-nl; LG-P700 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build\/IML74K) AppleWebkit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; LG-F160S Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; nl-nl; LG-E610v\/V10f Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; LG-E612 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; LG-F180K Build\/JZO54K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; LG-V500 Build\/JDQ39B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; LG-LW770 Build\/IMM76I) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; LG-V510 Build\/KOT49H.L004) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG E-900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-C900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-C900k)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-E900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-E900; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-E900h)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; LG; LG-Optimus 7)", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.0.1; ja-jp; L-06C Build\/HRI66) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.0; en-us; LG-V900 Build\/HRI39) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; en-gb; LG-V700 Build\/KOT49I.A1403851714) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.1599.103 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; LG-V500 Build\/KOT49I.V50020d) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; en-us; LG-V410\/V41010d Build\/KOT49I.V41010d) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.1599.103 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; LG-M257 Build\/NRD90U) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "LG", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; LM-G710 AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/74.0.3729.157 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2; xx-xx; HM NOTE 1W Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 MobilSafari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.1; zh-cn; MI-ONE Plus Build\/ITL41D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-cn; MI 2SC Build\/JRO03L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-cn; MI 2S Build\/JRO03L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; zh-tw; MI 1S Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.8; zh-cn; xiaomi2 Build\/GRK39F) AppleWebKit\/533.1 (KHTML, like Gecko)Version\/4.0 MQQBrowser\/4.4 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-es; MI 2A Build\/miui.es JRO03L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.1; zh-cn; MI 3 Build\/JOP40D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; MI 1S Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; MI 3W Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; HM 1SC Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; HM 1SW Build\/JLS36C) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/2.0.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; HM NOTE 1W Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/2.0.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; MI-ONE C1 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.4; en-us; MI 4W Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/2.0.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4; MI PAD Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/534.24 (KHTML, like Gecko) Chrome\/71.0.3578.141 Safari\/534.24 XiaoMi\/MiuiBrowser\/12.6.6-gn", + "mobile": false, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; POCOPHONE F1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/84.0.4147.125 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; MI 8) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/84.0.4147.125 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Redmi Note 9s) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/84.0.4147.125 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; en-gb; Redmi Note 5A Prime Build\/N2G47H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/71.0.3578.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 12; tr-tr; Redmi Note 10 Build\/SP1A.210812.016) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/100.0.4896.127 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/13.14.1-gn", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Safari\/537.36 Edge\/13.10586", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident\/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)", + "mobile": true, + "tablet": true, + "version": { + "IE": "10.0", + "Windows NT": "6.2", + "Trident": "6.0" + } + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident\/6.0)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident\/6.0; Touch)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident\/6.0; Touch; ARMBJS)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident\/6.0; Touch; MASMJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; WOW64; rv:25.0) Gecko\/20130626 Firefox\/25.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko\/20100101 Firefox\/22.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident\/6.0; MDDCJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident\/6.0; MDDCJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.52 Safari\/537.36 OPR\/15.0.1147.130", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.116 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident\/6.0; Touch; MDDCJS; WebView\/1.0)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident\/6.0; IEMobile\/10.0; ARM; Touch; Microsoft; Lumia 640 XL LTE)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident\/6.0; IEMobile\/10.0; ARM; Touch; NOKIA; Lumia 520)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident\/6.0; IEMobile\/10.0; ARM; Touch; NOKIA; Lumia 620)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident\/6.0; IEMobile\/10.0; ARM; Touch; NOKIA; Lumia 822)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 430 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 435) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 532) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 535) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 535) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537 BMID\/E679DAAB6F", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 640 LTE) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 1520) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537 UCBrowser\/4.2.1.541 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 520; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 530) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 620) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 625) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 630 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 630) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 635; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 735) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 820; Vodafone) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 830) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 925) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 930) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; ARM; Trident\/7.0; Touch; rv:11.0; WPDesktop; Lumia 635) like Gecko", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 640 Dual SIM) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950 XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 625) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 635) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 830) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/14.14295", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 930) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Mobile Safari\/537.36 Edge\/14.14295", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows Phone 8.1; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 530 Dual SIM) like Gecko", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; ARM; Lumia 950 XL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; ARM; Lumia 950) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; ARM; Lumia 930) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Microsoft", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; ARM; Lumia 730 Dual SIM) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2486.0 Safari\/537.36 Edge\/13.10586", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "MOT-W510\/08.11.05R MIB\/BER2.2 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 EGE\/1.0 UP.Link\/6.3.0.0.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.2; zh-cn; ME722 Build\/MLS2GC_2.6.0) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; en-us; DROIDX Build\/4.5.1_57_DX8-51) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; en-us; MB855 Build\/4.5.1A-1_SUN-254_13) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; es-us; MB526 Build\/4.5.2-51_DFL-50) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-ca; MB860 Build\/4.5.2A-51_OLL-17.8) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; en-us; MOT-XT535 Build\/V1.540) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; ko-kr; A853 Build\/SHOLS_U2_05.26.3; CyanogenMod-7.1.2) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.0; en-us; Xoom Build\/HRI39) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.1; en-us; Xoom Build\/HMJ25) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; DROID RAZR 4G Build\/6.7.2-180_DHD-16_M4-31) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; Xoom Build\/IMM76L) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; pt-br; XT687 Build\/V2.27D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.0.4", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "XT687" + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-es; MOT-XT910 Build\/6.7.2-180_SPU-19-TA-11.6) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT910 Build\/9.8.2O-124_SPUL-17) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT915 Build\/2_32A_2031) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT919 Build\/2_290_2017) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.64 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT925 Build\/9.8.2Q-50-XT925_VQLM-20) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT907 Build\/9.8.1Q-66) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT901 Build\/9.8.2Q-50_SLS-13) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; DROID BIONIC Build\/9.8.2O-72_VZW-22) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT1022 Build\/KXC20.82-14) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.4; en-in; XT1022 Build\/KXC21.5-40) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT1025 Build\/KXC20.82-13) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT1052 Build\/KLA20.16-2.16.2) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; XT1052 Build\/13.9.0Q2.X_83) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; XT1053 Build\/13.9.0Q2.X_61) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Mobile Safari\/537.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; XT1053 Build\/13.9.0Q2.X_55) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; XT1056 Build\/13.9.0Q2.X-116-MX-17-6-2) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.64 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT1031 Build\/KXB20.9-1.10-1.18-1.1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; XT1032 Build\/KXB21.14-L1.40) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; de-de; XT1032 Build\/KLB20.9-1.10-1.24-1.1) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.16", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT1034 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-us; XT1034 Build\/14.10.0Q3.X-84-16) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; XT1035 Build\/14.10.0Q3.X-23) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.3; XT1039 Build\/KXB21.14-L1.31) AppleWebKit\/537.36 (KHTML like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; XT919 Build\/2_290_2002) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT919 Build\/2_290_2004) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; XT920 Build\/2_290_2014) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; XT920 Build\/2_310_2014) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; XT905 Build\/7.7.1Q_GCIRD-16) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; XT908 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; XT897 Build\/7.7.1Q-6_SPR-ASANTI_LE-18) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; XT1032 Build\/LXB22.46-28.1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/43.0.2357.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; Moto E Build\/LMY47V) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/39.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; XT1021 Build\/KTU84Q) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; XT1068 Build\/LXB22.46-28) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Motorola", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; XT1092 Build\/MPE24.49-18) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Mpman", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; MPDC703 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mpman", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; fr-fr; MPDC706 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mpman", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; MPQC1010 Build\/KVT49L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Nexus 9 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; Nexus 9 Build\/LMY48T) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/51.0.2704.81 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; Nexus 9 Build\/N4F26M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.132 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; Nexus 9 Build\/NRD91N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.132 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Nexus 7 Build\/JRO03D)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Nexus 7 Build\/JRO03D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19 QBWebViewUA\/2 QBWebViewType\/1 WKType\/1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 7.1.1; zh-CN; Nexus 6 Build\/N6F27E) AppleWebKit\/537.51.1 (KHTML, like Gecko) Version\/4.0 Chrome\/40.0.2214.89 UCBrowser\/12.8.6.1274 Mobile Safari\/537.36 AliApp(TUnionSDK\/0.1.20.3)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Nexus 5X Build\/MMB29P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.92 Mobile Safari\/537.36 (compatible; Googlebot\/2.1; +http:\/\/www.google.com\/bot.html)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/78.0.3904.108 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-cn; Galaxy Nexus Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/5.0 Mb2345Browser\/9.4.1oem Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Nexus 5 Build\/MRA58N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/74.0.3694.0 Mobile Safari\/537.36 Chrome-Lighthouse", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "E-Mobile7\/7.0.37.20200806 (Linux;U;Android 10;Nexus One Build.FRG83) AppleWebKit\/553.1(KHTML,like Gecko) Version\/4.0 Mobile Safari\/533.1 Language\/zh Mode\/PCKM80 DeviceBrand\/OPPO IMEI\/fa3d88953a07b469 Qiyuesuo\/physicalSDK", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 5.1 en-us; Nexus One Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 baidubrowser\/4.5.0.0 (Baidu; P1 5.1)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Nexus 6 Build\/MMB29K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/76.0.3809.89 Mobile Safari\/537.36 T7\/11.21 SP-engine\/2.17.0 baiduboxapp\/11.21.0.10 (Baidu; P1 6.0.1)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nexus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4; en-us; Nexus 4 Build\/JOP24G) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Nokia200\/2.0 (12.04) Profile\/MIDP-2.1 Configuration\/CLDC-1.1 UCWEB\/2.0 (Java; U; MIDP-2.0; en-US; nokia200) U2\/1.0.0 UCBrowser\/8.9.0.251 U2\/1.0.0 Mobile UNTRUSTED\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Nokia6303iclassic\/5.0 (06.61) Profile\/MIDP-2.1 Configuration\/CLDC-1.1 Mozilla\/5.0 AppleWebKit\/420+ (KHTML, like Gecko) Safari\/420+", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "nokian73-1\/UC Browser7.8.0.95\/69\/400 UNTRUSTED\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Nokia2760\/2.0 (06.82) Profile\/MIDP-2.1 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Nokia3650\/1.0 SymbianOS\/6.1 Series60\/1.2 Profile\/MIDP-1.0 Configuration\/CLDC-1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "NokiaN70-1\/5.0737.3.0.1 Series60\/2.8 Profile\/MIDP-2.0 Configuration\/CLDC-1.1\/UC Browser7.8.0.95\/27\/352", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (S60V3; U; ru; NokiaN73) AppleWebKit\/530.13 (KHTML, like Gecko) UCBrowser\/8.6.0.199\/28\/444\/UCWEB Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (S60V3; U; ru; NokiaC5-00.2)\/UC Browser8.5.0.183\/28\/444\/UCWEB Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (S60V3; U; ru; NokiaC5-00.2) AppleWebKit\/530.13 (KHTML, like Gecko) UCBrowser\/8.7.0.218\/28\/352\/UCWEB Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Series40; NokiaC3-00\/08.63; Profile\/MIDP-2.1 Configuration\/CLDC-1.1) Gecko\/20100401 S40OviBrowser\/2.2.0.0.33", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Opera\/9.80 (Series 60; Opera Mini\/7.0.31380\/28.2725; U; es) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false, + "version": { + "Opera Mini": "7.0.31380", + "Presto": "2.8.119" + } + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.2 NokiaC7-00\/025.007; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.37 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.2 NokiaX7-00\/022.014; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.37 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 NokiaE6-00\/111.140.0058; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/535.1 (KHTML, like Gecko) NokiaBrowser\/8.3.1.4 Mobile Safari\/535.1 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 NokiaC6-01\/111.040.1511; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/535.1 (KHTML, like Gecko) NokiaBrowser\/8.3.1.4 Mobile Safari\/535.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 NokiaC6-01; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.4.2.6 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 Nokia700\/111.030.0609; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.4.2.6 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 Nokia700\/111.020.0308; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.4.1.14 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 NokiaN8-00\/111.040.1511; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/535.1 (KHTML, like Gecko) NokiaBrowser\/8.3.1.4 Mobile Safari\/535.1 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Symbian\/3; Series60\/5.3 Nokia701\/111.030.0609; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.4.2.6 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 Nokia6120c\/3.83; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 Nokia6120ci\/7.02; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 Nokia6120c\/7.10; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaE66-1\/510.21.009; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaE71-1\/110.07.127; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaN95-3\/20.2.011 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaE51-1\/200.34.36; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaE63-1\/500.21.009; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.2; U; Series60\/3.1 NokiaN82\/10.0.046; Profile\/MIDP-2.0 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaE52-1\/052.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.6.2", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaE52-1\/@version@; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.26 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaC5-00\/031.022; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.3.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaC5-00.2\/081.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.32 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; U; Series60\/3.2 NokiaN79-1\/32.001; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; U; Series60\/3.2 Nokia6220c-1\/06.101; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/413 (KHTML, like Gecko) Safari\/413", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaC5-00.2\/071.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.26 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaE72-1\/081.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.32 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.3; Series60\/3.2 NokiaC5-00\/061.005; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.6.2 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 NokiaX6-00\/40.0.002; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.33 Mobile Safari\/533.4 3gpp-gb", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 Nokia5800d-1\/60.0.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.33 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 NokiaC5-03\/12.0.023; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.6.9 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 Nokia5228\/40.1.003; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.7.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 Nokia5230\/51.0.002; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.33 Mobile Safari\/533.4 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 Nokia5530c-2\/32.0.007; Profile\/MIDP-2.1 Configuration\/CLDC-1.1 ) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 BrowserNG\/7.2.6.9 3gpp-gba", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 NokiaN97-1\/21.0.045; Profile\/MIDP-2.1 Configuration\/CLDC-1.1) AppleWebKit\/525 (KHTML, like Gecko) BrowserNG\/7.1.4", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (SymbianOS\/9.4; Series60\/5.0 NokiaN97-4\/30.0.004; Profile\/MIDP-2.1 Configuration\/CLDC-1.1) AppleWebKit\/533.4 (KHTML, like Gecko) NokiaBrowser\/7.3.1.28 3gpp-gba", + "mobile": true, + "tablet": false, + "version": { + "Symbian": "9.4", + "Webkit": "533.4", + "NokiaBrowser": "7.3.1.28" + }, + "model": "NokiaN97-4" + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; 7 Mozart T8698)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; 710)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; 800)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; 800C)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; 800C; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; 900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; HD7 T9292)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; LG E-900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 610)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 710)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 710; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 710; T-Mobile)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 710; Vodafone)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800) UP.Link\/5.1.2.6", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800; SFR)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800; T-Mobile)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800; vodafone)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; Lumia 800c)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; Lumia 920)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident\/6.0; IEMobile\/10.0; ARM; Touch; NOKIA; Lumia 920)", + "mobile": true, + "tablet": false, + "version": { + "IE": "10.0", + "Windows Phone OS": "8.0", + "Trident": "6.0" + }, + "model": "Lumia 920" + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; lumia800)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Nokia 610)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Nokia 710)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Nokia 800)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Nokia 800C)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Nokia 900)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; Nokia)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; SGH-i917)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Nokia; TITAN X310e)", + "mobile": true, + "tablet": false, + "version": { + "Windows Phone OS": "7.5", + "Trident": "5.0" + }, + "model": "TITAN X310e" + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Windows Phone 10.0; Android 4.2.1; NOKIA; Lumia 635) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.135 Mobile Safari\/537.36 Edge\/12.10166", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "Mozilla\/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident\/7.0; Touch; rv:11.0; IEMobile\/11.0; Microsoft; Lumia 535 Dual SIM) like iPhone OS 7_0_3 Mac OS X AppleWebKit\/537 (KHTML, like Gecko) Mobile Safari\/537", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nokia", + "user_agent": "NokiaC3-01.5\/5.0 (07.58) Profile\/MIDP-2.1 Configuration\/CLDC-1.1 Mozilla\/5.0 AppleWebKit\/420+ (KHTML, like Gecko) Safari\/420+", + "mobile": true, + "tablet": false + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; V975i Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.108 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Android; Tablet; rv:37.0) Gecko\/37.0 Firefox\/37.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; V975m Core4 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; fr-fr; V975m Core4 Build\/JSS15J) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Safari\/537.16", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; V975m Core4 Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/41.0.2272.96 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; V812 Core4 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Onda", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; V10 4G Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/62.0.3202.94 YaBrowser\/17.11.1.628.01 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "AdvanDigital", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; E1C Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "AdvanDigital", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; id-id; T3C Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Ainol", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; en-us; Ainol Novo8 Advanced Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Ainol", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Novo10 Hero Build\/20121115) AppleWebKit\/535.19 (KHTML like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Ainol", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; es-es; novo9-Spark Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "AllFine", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; FINE7 GENIUS Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Amoi", + "user_agent": "Amoi 8512\/R18.0 NF-Browser\/3.3", + "mobile": true, + "tablet": false, + "model": "8512" + }, + { + "vendor": "Arnova", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; fr-fr; AN9G2I Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "AudioSonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-au; T-17B Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Blaupunkt", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; Endeavour 800NG Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Broncho", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; es-es; Broncho N701 Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-es; bq Livingstone 2 Build\/1.1.7 20121018-10:33) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-es; bq Edison Build\/1.1.10-1015 20121230-18:00) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; Maxwell Lite Build\/v1.0.0.ICS.maxwell.20120920) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; zh-tw; bq Maxwell Plus Build\/1.0.0 20120913-10:39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Aquaris E10 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; Aquaris M10 Build\/LMY47I) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/47.0.2526.83 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Aquaris M10 FHD Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Aquaris M8 Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/60.0.3112.116 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; Aquaris E5 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; Aquaris E5 HD Build\/LRX21M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/55.0.2883.91 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; Aquaris_M4.5 Build\/MRA58K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/51.0.2704.81 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; Aquaris X5 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/52.0.2743.91 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; Aquaris E4 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/61.0.3163.98 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "bq", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; Aquaris M5 Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/61.0.3163.98 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Captiva", + "user_agent": "Opera\/9.80 (X11; Linux zvav; U; de) Presto\/2.8.119 Version\/11.10 Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; CAPTIVA PAD 10.1 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Casio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-us; C771 Build\/C771M120) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "ChangJia", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; pt-br; TPC97113 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "ChangJia", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; TPC7102 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Celkon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; Celkon CT 910+ Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Celkon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-in; CT-1 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Celkon", + "user_agent": "CELKON.C64\/R2AE SEMC-Browser\/4.0.3 Profile\/MIDP-2.0 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Celkon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; Celkon A125 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Celkon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-US; Celkon*A86 Build\/Celkon_A86) AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1 UCBrowser\/8.7.0.315 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Celkon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; Celkon A.R 40 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Coby", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; en-us; MID7010 Build\/FRF85B) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Coby", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; MID7048 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Coby", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; MID8042 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Concorde", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; hu-hu; ConCorde Tab T10 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Concorde", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; hu-hu; ConCorde tab PLAY Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Cresta", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; nl-nl; CRESTA.CTP888 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Cube", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru-ru; CUBE U9GT 2 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Danew", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; es-es; Dslide 700 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "IML74K", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "Dslide 700" + }, + { + "vendor": "DanyTech", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Genius Tab Q4 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Digma", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru-ru; iDx10 3G Build\/ICS.b02ref.20120331) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "DPS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; DPS Dream 9 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "ECS", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; it-it; TM105A Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "IMM76D", + "Webkit": "534.30" + } + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme Dual Core X190 Build\/JRO03C) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Essential A160 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; E-Boda Supreme X80 Dual Core Build\/ICS.g12refM806A1YBD.20120925) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; E-boda essential smile Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme X80 Dual Core Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Eboda", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; E-Boda Supreme XL200IPS Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Evolio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; Evolio X7 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Evolio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ro-ro; ARIA_Mini_wifi Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Fly", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; Fly IQ440; Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Fly", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; FLY IQ256 Build\/GRK39F) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Fujitsu", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ja-jp; F-10D Build\/V21R48A) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "V21R48A", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Fujitsu", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; ru-ru; M532 Build\/IML74K) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "IML74K", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "FX2", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; FX2 PAD7 RK Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Galapad", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-tw; G1 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Webkit": "534.30", + "Safari": "4.0", + "Build": "JRO03C" + } + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; el-gr; GOCLEVER TAB A103 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; zh-tw; A7GOCLEVER Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; GOCLEVER TAB A104 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; cs-cz; GOCLEVER TAB A93.2 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; sk-sk; GOCLEVER TAB A971 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; lv-lv; GOCLEVER TAB A972BK Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; fr-fr; GOCLEVER TAB A104.2 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GoClever", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; pt-pt; GOCLEVER TAB T76 Build\/MID) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "GU", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; vi-vn; TX-A1301 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "IMM76D", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "GU", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; da-dk; Q702 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "IML74K", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "HCL", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; U1 Build\/HCL ME Tablet U1) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "HCL", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; U1 Build\/HCL ME Tablet U1) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "HCL", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; Connect-3G-2.0 Build\/HCL) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "HCL", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; pt-br; X1 Build\/HCL ME Tablet X1) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Hisense", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; F5281 Build\/KTU84Q) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/260.1985.135 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Hudl", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Hudl HT7S3 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.82 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Iconbit", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; NT-3702M Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Safari\/537.36 OPR\/16.0.1212.65583", + "mobile": true, + "tablet": true + }, + { + "vendor": "Iconbit", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; NetTAB SPACE II Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "iJoy", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; fr-fr; Tablet Planet II-v3 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Intenso", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1.;de-de; INM8002KP Build\/JR003H) AppleWebKit\/534.30 (KHTML, like Gecko)Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1.", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Intenso", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; TAB1004 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "INQ", + "user_agent": "INQ1\/R3.9.12 NF-Browser\/3.5", + "mobile": true, + "tablet": false, + "model": "INQ1" + }, + { + "vendor": "Intex", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3; en-US; Cloud_X2 Build\/MocorDroid4.0.1) AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1 UCBrowser\/9.2.0.419 Mobile", + "mobile": true, + "tablet": false + }, + { + "vendor": "Intex", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; Cloud Y2 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Intex", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-in; Cloud X5 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "IRU", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; M702pro Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "JXD", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; F3000 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Karbonn", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; ST10 Build\/JRO03C) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "KRAMER", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; KT107 Build\/LMY47I) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/64.0.3282.137 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Kobo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.0; en-us;) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 (Kobo Touch)", + "mobile": true, + "tablet": true, + "version": { + "Android": "2.0", + "Webkit": "533.1", + "Safari": "4.0" + } + }, + { + "vendor": "Megafon", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; ru-ru; MegaFon V9 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Megafon", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; MT7A Build\/JRO03C) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Safari\/537.31", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mediacom", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; M-MPI10C3G Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/64.0.3282.137 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Mediacom", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0; M-SP10HXAH Build\/MRA58K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/59.0.3071.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "MediaTek", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; fr-fr; MT8377 Build\/JRO03C) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30\/4.05d.1002.m7", + "mobile": true, + "tablet": true + }, + { + "vendor": "Micromax", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Micromax A110 Build\/JRO03C) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.169 Mobile Safari\/537.22", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.1.1", + "Build": "JRO03C", + "Webkit": "537.22", + "Chrome": "25.0.1364.169" + } + }, + { + "vendor": "Micromax", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0; xx-xx; Micromax P250(Funbook) Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Webkit": "534.30", + "Android": "4.0", + "Build": "IMM76D", + "Safari": "4.0" + } + }, + { + "vendor": "Modecom", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; pl-pl; FreeTAB 1014 IPS X4+ Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "MSI", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.5; el-gr; MSI Enjoy 10 Plus Build\/1.2) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nabi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; en-us; NABI-A Build\/MASTER) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "NEC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ja-jp; N-08D Build\/A5001911) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "NEC", + "user_agent": "Mozilla\/5.0 (Linux; U; Android AAA; BBB; N-06D Build\/CCC) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nexo", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; pl-pl; NEXO 3G Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30 ACHEETAHI\/2100050074", + "mobile": true, + "tablet": true + }, + { + "vendor": "Nibiru", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-tw; Nibiru H1 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 XiaoMi\/MiuiBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Nook", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; en-us; NOOK BNRV200 Build\/ERD79 1.4.3) Apple WebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true, + "version": { + "Android": "2.2.1", + "Webkit": "533.1", + "Safari": "4.0" + } + }, + { + "vendor": "Nook", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; NOOK BNTV400 Build\/ICS) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "ICS", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Nook", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; BNTV600 Build\/IMM76L) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36 Hughes-PFB\/CID5391275.AID1376709964", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "IMM76L", + "Webkit": "537.36", + "Chrome": "28.0.1500.94" + } + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; A0001 Build\/JLS36C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; xx-xx; A0001 Build\/JLS36C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; ONEPLUS A5000 Build\/NMF26X; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/60.0.3112.116 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; ONEPLUS A5010 Build\/OPM1.171019.011; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/66.0.3359.126 Mobile Safari\/537.36 [FB_IAB\/Orca-Android;FBAV\/164.0.0.24.95;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; ONEPLUS A3010) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.185 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Oneplus", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; KB2003) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; LOOX Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; LOOX Plus Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.X; de-de; XENO10 Build\/ODYS XENO 10) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.2; de-de; ODYS Space Build\/I700T_P7_T04_TSCL_FT_R_0_03_1010_110623) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; ODYS-EVO Build\/ODYS-EVO) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.X; de-de; Xelio 10 Pro Build\/ODYS_Xelio) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; NEO_QUAD10 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.X; de-de; Xelio10Pro Build\/ODYS_Xelio) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.1; en-us; ODYS-Xpress Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; de-de; XELIO7PHONETAB Build\/IMM76I) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; XELIO10EXTREME Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; de-de; XELIO Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30 Mobile UCBrowser\/3.2.1.441", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; XELIOPT2 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Odys", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; nl-nl; ODYS-NOON Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "OverMax", + "user_agent": "OV-SteelCore(B) Mozilla\/5.0 (iPad; CPU OS 5_0_1 like Mac OS X) AppleWebKit\/534.46 (KHTML, like Gecko) Version\/5.1 Mobile\/9A405 Safari\/7534.48.3", + "mobile": true, + "tablet": true + }, + { + "vendor": "OverMax", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; pl-pl; OV-SteelCore Build\/ICS.g08refem611.20121010) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "OverMax", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0.99; Qualcore 1027 4G Build\/LMY47D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/60.0.3112.116 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "YONESTablet", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; pl-pl; BC1077 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Pantech", + "user_agent": "PANTECH-C790\/JAUS08312009 Browser\/Obigo\/Q05A Profile\/MIDP-2.0 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pantech", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; ko-kr; SKY IM-A600S Build\/FRG83) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pantech", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-us; ADR8995 4G Build\/GRI40) AppleWebKit\/533.1 (KHTML like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Pantech", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2.1; en-us; PantechP4100 Build\/HTK75) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; Philips W336 Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.45 Mobile Safari\/537.36 OPR\/15.0.1162.59192", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Philips_T3500\/V1 Linux\/3.4.5 Android\/4.2.2 Release\/03.26.2013 Browser\/AppleWebKit534.30 Mobile Safari\/534.30 MBBMS\/2.2 System\/Android 4.2.2;", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Philips W3568 Build\/Philips_W3568) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; Philips W832 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux;U;Android 4.2.2;es-us;Philips S388 Build\/JDQ39) AppleWebkit\/534.30 (HTML,like Gecko) Version\/4.0 Mobile Safari\/534.30;", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; Philips W536 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux;U;Android 4.2.2;es-us;Philips S308 Build\/JDQ39) AppleWebkit\/534.30 (HTML,like Gecko) Version\/4.0 Mobile Safari\/534.30;", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; ru-ru; Philips-W8500 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; ru; Philips W8510 Build\/JDQ39) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.8.9.457 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; ru-RU; Philips W3568 Build\/Philips W3568) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.1 Mobile Safari\/534.30;", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; Philips S388 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; Build\/PI3100.00.00.24) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; W732 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Philips", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.1; PI7100_93 Build\/PI7100.C.00.00.11) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "PocketBook", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; en-ru; PocketBook A10 3G Build\/GRJ90) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "PointOfView", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; POV_TAB-PROTAB30-IPS10 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Polaroid", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; MID4X10 Build\/LMY47V) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/48.0.2564.95 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Praktica", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; TP750 3GGSM Build\/IMM76I) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "PROSCAN", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; PLT8088 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Build": "JRO03H", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "PyleAudio", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; PTBL92BC Build\/IMM76D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Mobile Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "IMM76D", + "Webkit": "537.36", + "Chrome": "31.0.1650.59" + } + }, + { + "vendor": "Realme", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 10; en-us; RMX1919 Build\/QKQ1.200209.002) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/70.0.3538.80 Mobile Safari\/537.36 HeyTapBrowser\/45.7.1.9", + "mobile": true, + "tablet": false + }, + { + "vendor": "RockChip", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; hu-hu; RK2818, Build\/MASTER) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "RockChip", + "user_agent": "Mozilla\/5.0 (Linux; U; Android Android 2.1-RK2818-1.0.0; zh-cn; MD701 Build\/ECLAIR) AppleWebKit\/530.17 (KHTML like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": true + }, + { + "vendor": "RossMoor", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.1; ru-ru; RM-790 Build\/JOP40D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "QMobile", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; A2 Build\/GRK39F) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "simvalley", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; de-de; SP-80 Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Skk", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1; en-us; CYCLOPS Build\/F10) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Storex", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; eZee_Tab903 Build\/JRO03H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Build": "JRO03H", + "Webkit": "537.36" + } + }, + { + "vendor": "Storex", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; eZee'Tab785 Build\/JRO03C) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.59 Safari\/537.36", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Build": "JRO03C", + "Webkit": "537.36" + } + }, + { + "vendor": "Storex", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; eZee'Tab971 Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "IML74K", + "Webkit": "535.19" + } + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; P98 3G\\xE5\\x85\\xAB\\xE6\\xA0\\xB8(A3HY) Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "QQ\\xe9\\x9f\\xb3\\xe4\\xb9\\x90HD 4.0.1 (iPad; iPhone OS 8.0; zh_CN)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0; xx-xx; A15(E6C2) Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3; xx-xx; A10 Build\/GRJ22) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; Teclast A10T Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; zh-cn; Teclast P85(A9D3) Build\/IMM76D) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Teclast", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; A70H Build\/JDQ39) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.8.0.435 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Tecno", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; TECNO P9 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Tecno", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; TECNO DP8D Build\/LMY47D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/49.0.2623.91 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Telstra", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; en-au; T-Hub2 Build\/TVA301TELBG3) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "texet", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; ru-ru; TM-7021 Build\/GB.m1ref.20120116) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true, + "version": { + "Android": "2.3.4", + "Webkit": "533.1", + "Safari": "4.0" + }, + "model": "TM-7021" + }, + { + "vendor": "Tolino", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 7 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "JDQ39", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Tolino", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 8.9 Build\/JDQ39) AppleWebKit\/534.30 (KHTML like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "JDQ39", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Tolino", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; tolino tab 7 Build\/JDQ39) AppleWebkit\/537.36 (KHTML, like Gecko) Chrome\/31.0.1650.57 Safari\/537.36 OPR\/18.0.1290.67495", + "mobile": true, + "tablet": true + }, + { + "vendor": "Tolino", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; tolino tab 7 Build\/JDQ39) AppleWebkit\/537.36 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Toshiba", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; TOSHIBA; TSUNAGI)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Toshiba", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; it-it; TOSHIBA_FOLIO_AND_A Build\/TOSHIBA_FOLIO_AND_A) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true, + "version": { + "Android": "2.2", + "Webkit": "533.1", + "Safari": "4.0" + } + }, + { + "vendor": "Trekstor", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; ST70408-1 Build\/JDQ39) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Safari\/537.31", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "JDQ39", + "Webkit": "537.31", + "Chrome": "26.0.1410.58" + } + }, + { + "vendor": "Trekstor", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; engb; Build\/IMM76D) AppleWebKit\/534.46 (KHTML, like Gecko) Version\/5.1 Mobile\/9A405 Safari\/7534.48.3 SurfTab_7.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Trekstor", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; VT10416-2 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Trekstor", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; de-de; ST10216-2A Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30;SurfTab_10.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Tsmine", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; TM1088 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Ubislate", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; UBISLATE7C+ Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "WeVool", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; WVT101 Build\/LRX21M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Visture", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; V97 HD Build\/LR-97JC) Apple WebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Visture", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; Visture V4 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Visture", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; Visture V4 HD Build\/Visture V4 HD) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Visture", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; es-es; Visture V5 HD Build\/Visture V5 HD) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Visture", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; Visture V10 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vivo", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; vivo 1951) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Versus", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; VS-TOUCHPAD 9 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Versus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-gb; Versus Touchpad 9.7 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Versus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-gb; CnM-TOUCHPAD7 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30 BMID\/E67A45B1AB", + "mobile": true, + "tablet": true + }, + { + "vendor": "Versus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; CnM TouchPad 7DC Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30 TwonkyBeamBrowser\/3.3.5-95 (Android 4.1.1; rockchip CnM TouchPad 7DC Build\/meizhi_V2.80.wifi8723.20121225.b11c800)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Versus", + "user_agent": "OneBrowser\/3.5\/Mozilla\/5.0 (Linux; U; Android 4.0.4; en-gb; TOUCHPAD 7 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Versus", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; TOUCHTAB Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.1", + "Build": "JRO03H", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; de-de; ViewPad 10e Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; it-it; ViewPad7 Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; en-ca; ViewSonic VB733 Build\/FRG83) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; en-gb; ViewPad7X Build\/HTJ85B) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; pt-br; ViewPad 10S Build\/FRF91) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Viewsonic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; VB100a Pro Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vonino", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-us; Sirius_Evo_QS Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vonino", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; Q8 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Wolder", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4; miTab LIVE Build\/KVT49L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Wolder", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; pt-pt; miTab FUNK Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Wolfgang", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.1; nl-nl; AT-AS45q2 Build\/JOP40D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xoro", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; PAD 9720QR Build\/PAD 9719QR) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Xoro", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; PAD720 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "ZTE", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; V8200plus Build\/IMM76I) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "ZTE", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 7.1.2; zh-cn; Z999 Build\/N2G47H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.132 MQQBrowser\/8.4 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "ZTE", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; Z999 Build\/N2G47H; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Mobile Safari\/537.36 T7\/10.11 light\/1.0 baiduboxapp\/10.11.0.13 (Baidu; P1 7.1.2)", + "mobile": true, + "tablet": false + }, + { + "vendor": "ZTE", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; Z999 Build\/N2G47H; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.132 MQQBrowser\/6.2 TBS\/044403 Mobile Safari\/537.36 MMWEBID\/8089 MicroMessenger\/6.7.3.1360(0x26070339) NetType\/WIFI Language\/zh_CN", + "mobile": true, + "tablet": false + }, + { + "vendor": "ZTE", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Z999 Build\/OPM1.171019.019; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/64.0.3282.137 Mobile Safari\/537.36 NewsApp\/49.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Zync", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-us ; Z909 Build\/GRI40) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1\/UCBrowser\/8.4.1.204\/145\/444", + "mobile": true, + "tablet": true + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 11; zh-cn; Mi 10 Build\/RKQ1.200826.002) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/89.0.4389.116 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/15.8.6", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; Redmi 5A) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/96.0.4664.45 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 11; zh-cn; M2012K11C Build\/RKQ1.201112.002) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/89.0.4389.116 Mobile Safari\/537.36 XiaoMi\/MiuiBrowser\/15.7.20", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; Redmi Note 7 Pro) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/95.0.4638.74 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; 21051182G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/94.0.4606.85 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; 21081111RG) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/106.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Xiaomi", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; M2007J1SC) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/101.0.4951.48 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; PMP5297C_QUAD Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; sk-sk; PMP7100D3G Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.4", + "Build": "IMM76D", + "Webkit": "534.30", + "Safari": "4.0" + }, + "model": "PMP7100D3G" + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; sk-sk; PMP7280C3G Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 MobilSafari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; PMT3017_WI Build\/KVT49L) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; PMT3037_3G Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; PMT5002_Wi Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/39.0.2171.93 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Prestigio", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; el-gr; PMT5887_3G Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "MQQBrowser\/4.0\/Mozilla\/5.0 (Linux; U; Android 3.2; zh-cn; GT-P6800 Build\/HTJ85B) AppleWebKit\/533.1 (KHTML, like Gecko) Mobile Safari\/533.1", + "mobile": true, + "tablet": true, + "version": { + "MQQBrowser": "4.0" + } + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-SGH-P250-ORANGE\/P250BVHH8 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 UP.Browser\/6.2.3.3.c.1.101 (GUI) MMP\/2.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-GT-B2710\/B271MCXKF1 SHP\/VPP\/R5 Dolfin\/2.0 QTV\/5.3 SMM-MMS\/1.2.0 profile\/MIDP-2.1 configuration\/CLDC-1.1 OPN-B", + "mobile": true, + "tablet": false, + "version": { + "Dolfin": "2.0" + } + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-SGH-D900i\/1.0 Profile\/MIDP-2.0 Configuration\/CLDC-1.1 UP.Browser\/6.2.3.3.c.1.101 (GUI) MMP\/2.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-GT-S5233T\/S5233TXEJE3 SHP\/VPP\/R5 Jasmine\/0.8 Qtv5.3 SMM-MMS\/1.2.0 profile\/MIDP-2.1 configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (SAMSUNG; SAMSUNG-GT-S5380D\/S5380FXXKL3; U; Bada\/2.0; ru-ru) AppleWebKit\/534.20 (KHTML, like Gecko) Dolfin\/3.0 Mobile HVGA SMM-MMS\/1.2.0 OPN-B", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-GT-C3312\/1.0 NetFront\/4.2 Profile\/MIDP-2.0 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 1.5; de-de; Galaxy Build\/CUPCAKE) AppleWebKit\/528.5 (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-GT-S3650\/S3650XEII3 SHP\/VPP\/R5 Jasmine\/1.0 Nextreaming SMM-MMS\/1.2.0 profile\/MIDP-2.1 configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "JUC (Linux; U; 2.3.6; zh-cn; GT-S5360; 240*320) UCWEB7.9.0.94\/140\/352", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (SAMSUNG; SAMSUNG-GT-S5250\/S5250XEKJ3; U; Bada\/1.0; ru-ru) AppleWebKit\/533.1 (KHTML, like Gecko) Dolfin\/2.0 Mobile WQVGA SMM-MMS\/1.2.0 NexPlayer\/3.0 profile\/MIDP-2.1 configuration\/CLDC-1.1 OPN-B", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident\/3.1; IEMobile\/7.0; SAMSUNG; SGH-i917)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (SAMSUNG; SAMSUNG-GT-S8530\/S8530XXJKA; U; Bada\/1.2; cs-cz) AppleWebKit\/533.1 (KHTML, like Gecko) Dolfin\/2.2 Mobile WVGA SMM-MMS\/1.2.0 OPN-B", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 1.6; ru-ru; Galaxy Build\/Donut) AppleWebKit\/528.5+ (KHTML, like Gecko) Version\/3.1.2 Mobile Safari\/525.20.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; ru-ru; GT-I5500 Build\/ERE27) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; en-us; GALAXY_Tab Build\/MASTER) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; ja-jp; SC-01C Build\/FROYO) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2; fr-fr; GT-I9000 Build\/FROYO) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.2.1; zh-cn; SCH-i909 Build\/FROYO) UC AppleWebKit\/534.31 (KHTML, like Gecko) Mobile Safari\/534.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; ja-jp; SC-01C Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-gb; GT-P1000 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; el-gr; GT-I9001 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-ca; SGH-I896 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; es-us; GT-S5660L Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1 MicroMessenger\/4.5.1.261", + "mobile": true, + "tablet": false, + "version": { + "MicroMessenger": "4.5.1.261" + } + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; GT-S5660 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S6102 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; pt-br; GT-S5367 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; fr-fr; GT-S5839i Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S7500 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S5830 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; es-us; GT-B5510L Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; pl-pl; GT-I9001-ORANGE\/I9001BVKPC Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; GT-I8150 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; nl-nl; GT-I9070 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-gb; GT-S5360 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; es-us; GT-S6102B Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-us; GT-S5830i Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-I8160 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-S6802 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; ru-ru; GT-S5830 Build\/GRWK74; LeWa_ROM_Cooper_12.09.21) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; ru-ru; GT-N7000 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.0.1; en-us; GT-P7100 Build\/HRI83) AppleWebkit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; he-il; GT-P7300 Build\/HTJ85B) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; en-gb; GT-P6200 Build\/HTJ85B) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0 Safari\/534.13", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-gb; GT-I9100 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9100G Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; nl-nl; GT-P5100 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build\/IML74K) AppleWebKit\/535.7 (KHTML, like Gecko) CrMo\/16.0.912.75 Mobile Safari\/535.7", + "mobile": true, + "tablet": false, + "version": { + "Chrome": "16.0.912.75" + } + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; SGH-T989 Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false, + "version": { + "Chrome": "18.0.1025.166" + } + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P5100 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; GT-I9300 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; SPH-D710 Build\/IMM76I) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; zh-cn; GT-I9300 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300-ORANGE\/I9300BVBLG2 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; th-th; GT-I9300T Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-I9100 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us ; GT-I9100 Build\/IMM76D) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1\/UCBrowser\/8.4.1.204\/145\/355", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-gb; GT-N7000 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; th-th; GT-P6800 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; SAMSUNG-SGH-I747 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; es-es; GT-P5110 Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; GT-P5110 Build\/IMM76D) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; zh-cn; SAMSUNG-GT-S7568_TD\/1.0 Android\/4.0.4 Release\/07.15.2012 Browser\/AppleWebKit534.30 Build\/IMM76D) ApplelWebkit\/534.30 (KHTML,like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false, + "version": { + "Android": "4.0.4" + } + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-P3100 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; tr-tr; GT-P3105 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-ca; GT-N8010 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; ru-ru; GT-S7562 Build\/IMM76I) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; GT-N7100 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; GT-N7100 Build\/JZO54K) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.123 Mobile Safari\/537.22 OPR\/14.0.1025.52315", + "mobile": true, + "tablet": false, + "version": { + "Build": "JZO54K", + "Webkit": "537.22", + "Opera": "14.0.1025.52315" + } + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; zh-hk; GT-N7105 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; ru-ru; GT-N8000 Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.1; SGH-i747M Build\/JRO03L) AppleWebKit\/535.19(KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-gb; Galaxy Nexus - 4.1.1 - with Google Apps - API 16 - 720x1280 Build\/JRO03S) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; GT-I8262 Build\/JZO54K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; it-it; Galaxy Nexus Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; SGH-I777 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; GT-S7710 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; GT-I9082 Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; SGH-T999L Build\/JZO54K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; GT-P5210 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, Like Gecko) Chrome\/27.0.1453.90 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; en-us; SAMSUNG GT-I9200 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Version\/1.0 Chrome\/18.0.1025.308 Mobile Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; zh-cn; SCH-I959 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Version\/1.0 Chrome\/18.0.1025.308 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; nl-nl; SM-T310 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; en-us; SAMSUNG SM-P600 Build\/JSS15J) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; en-gb; GT-N5100 Build\/JDQ39) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-T530NU Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-T800 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; fr-fr; SAMSUNG SM-T800 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-T700 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.517 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; CETUS)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; Focus I917 By TC)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; Focus i917)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; FOCUS S)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; GT-I8350)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; GT-i8700)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; GT-S7530)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; Hljchm's Wp)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; I917)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; OMNIA 7)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; OMNIA7 By MWP_HS)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; OMNIA7)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; OMNIA7; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SGH-i677)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SGH-i917)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SGH-i917.)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SGH-i917R)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SGH-i937)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG; SMG-917R)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG_blocked_blocked_blocked; OMNIA7; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SAMSUNG_blocked_blocked_blocked_blocked; OMNIA7; Orange)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; SUMSUNG; OMNIA 7)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; ARM; Trident\/7.0; Touch; rv:11.0; WPDesktop; SAMSUNG; GT-I8750) like Gecko", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; ARM; Trident\/7.0; Touch; rv:11.0; WPDesktop; GT-I8750) like Gecko", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; en-gb; SAMSUNG GT-I9205 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Version\/1.0 Chrome\/18.0.1025.308 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; GT-P7510 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; SHV-E160K\/VI10.1802 Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SM-T805 Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/43.0.2357.92 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-T116NQ Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/43.0.2357.92 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SM-G9250 Build\/LRX22G; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/43.0.2357.121 Mobile Safari\/537.36 [FB_IAB\/FB4A;FBAV\/35.0.0.48.273;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-T705Y Build\/KOT49H) AppleWebKit\/537.36(KHTML, like Gecko) Chrome\/42.0.2311.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; GT-I9505 Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-T705 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/41.0.2272.45 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-T533 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/33.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-T533 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SM-T357T Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/48.0.2564.95 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SM-T357T Build\/LRX22G; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.106 Safari\/537.36 [FB_IAB\/FB4A;FBAV\/66.0.0.33.73;]", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-G9350 Build\/MMB29M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/46.0.2490.76 Mobile Safari\/537.36 MicroMessenger\/6.3.13.49_r4080b63.740 NetType\/cmnet Language\/zh_CN", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; 404SC Build\/?buildID?) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/42.0.2311.111 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-T560 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/40.0.2214.109 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-T561 Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/48.0.2564.95 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.6; en-ph; GT-S5300 Build\/GINGERBREAD) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SANSUNG SM-T555 Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.3 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "SAMSUNG-GT-C3310R\/1.0 NetFront\/4.2 Profile\/MIDP-2.0 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; SAMSUNG SM-J120F Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.5 Chrome\/38.0.2125.102 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T713 Build\/MMB29M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/54.0.2840.68 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T580 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.68 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T355Y Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/53.0.2785.124 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T280 Build\/LMY47V) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.5 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SM-G920F Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-G920F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-G920V Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/52.0.2743.98 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-G930F Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; SM-N910C Build\/KTU84P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/54.0.2840.85 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T817A Build\/LMY47X; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/52.0.2743.98 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T670 Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.5 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SM-T670 Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T677A Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T677A Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.5 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SM-T677V Build\/LMY47X) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/52.0.2743.98 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-P580 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-P580 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T587P Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T587P Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SAMSUNG SM-P350 Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.3 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-P350 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-G950F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-G955F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T355Y Build\/MMB29M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T355Y Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T355Y Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.2 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T355 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/59.0.3071.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-A310F Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F\/A310FXXU2BQB1 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-A310F Build\/MMB29K; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/58.0.3029.83 Mobile Safari\/537.36 [FB_IAB\/MESSENGER;FBAV\/118.0.0.19.82;]", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F\/XXU2BQB6 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SM-A310F Build\/LMY47X; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/58.0.3029.83 Mobile Safari\/537.36 BingWeb\/6.9.25207603", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SAMSUNG SM-A310F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.4 Chrome\/51.0.2704.106 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; en-gb; SAMSUNG GT-I9190 Build\/JDQ39) AppleWebKit\/535.19 (KHTML, like Gecko) Version\/1.0 Chrome\/18.0.1025.308 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; GT-I9190 Build\/MOB30Z) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/55.0.2883.91 Mobile Safari\/537.36 OPR\/42.7.2246.114996", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A510F\/A510FXXU4BQD1 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.4 Chrome\/51.0.2704.106 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T535\/T535XXU1BQC1 Build\/LRX22G) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.3 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500FN\/J500FNXXU1BQE2 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.4 Chrome\/51.0.2704.106 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; SAMSUNG SM-N9005\/N9005XXSGBQA1 Build\/LRX21V) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.4 Chrome\/51.0.2704.106 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G903F\/G903FXXU1BQC1 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.4 Chrome\/51.0.2704.106 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SAMSUNG SM-T285 Build\/LMY47V) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/3.5 Chrome\/38.0.2125.102 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T585 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SAMSUNG SM-T585 Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/4.0 Chrome\/44.0.2403.133 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SAMSUNG SM-T585 Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/5.2 Chrome\/51.0.2704.106 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; SM-W708YZKAXTC Build\/LMY48Z) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/39.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-G900F Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; SM-G950F Build\/NRD90M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/60.0.3112.116 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SAMSUNG-SM-N900A Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SAMSUNG SM-J330F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/6.4 Chrome\/56.0.2924.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SM-T835) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/74.0.3729.136 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SAMSUNG SM-T830 Build\/PPR1.180610.011) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser\/8.0 Chrome\/63.0.4349.111 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SAMSUNG SM-T837V Build\/M1AJQ) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser\/9.2 Chrome\/67.0.3396.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T720) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser\/8.0 Chrome\/74.0.3729.157 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T510) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser\/8.0 Chrome\/74.0.3729.157 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SM-T387V) AppleWebKit 537.36 (KHTML, like Gecko) SamsungBrowser\/8.0 Chrome\/74.0.3729.157 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-G610F Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/68.0.3440.91 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-P610) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/81.0.4044.138 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-T290) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/85.0.4183.81 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-G981B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.162 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SAMSUNG SM-T515) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/10.1 Chrome\/71.0.3578.99 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T590 Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/74.0.3729.157 Safari\/537.36 OPR\/53.1.2569.142848", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SAMSUNG SM-T590 Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/9.2 Chrome\/67.0.3396.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SAMSUNG SM-T595 Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/9.4 Chrome\/67.0.3396.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SAMSUNG SM-T725 Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/9.4 Chrome\/67.0.3396.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T817P Build\/MMB29K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-T817P Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/61.0.3163.98 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SM-P585N0) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/78.0.3904.90 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T295) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/84.0.4147.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SAMSUNG SM-T865) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/11.2 Chrome\/75.0.3770.143 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T865) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/83.0.4103.106 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SM-T970) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/88.0.4324.152 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; SM-G892A Build\/NRD90M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/67.0.3396.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-A530F) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.132 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-T860 Build\/QP1A.190711.020; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.163 Whale\/1.0.0.0 Crosswalk\/25.80.14.7 Safari\/537.36 NAVER(inapp; search; 710; 10.23.5)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; SM-T380) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/80.0.3987.149 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SM-T380C Build\/M1AJQ; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/66.0.3359.126 MQQBrowser\/6.2 TBS\/045118 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-T380 Build\/PPR1.180610.011; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/63.0.3239.83 Mobile Safari\/537.36 T7\/11.11 baiduboxapp\/11.11.0.12 (Baidu; P1 9)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 9; zh-CN; SM-T380 Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.108 UCBrowser\/12.4.0.1020 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SM-T231 Build\/KOT49H; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/48.0.2564.116 Safari\/537.36 baiduboxapp\/8.6.5 (Baidu; P1 4.4.2)", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; zh-cn; SAMSUNG SM-T231 Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-T500) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/88.0.4324.152 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; SM-G988N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/94.0.4606.85 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; SM-T536) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/94.0.4606.85 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.80 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-G781B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Mobile Safari\/537.36 EdgA\/105.0.1343.50", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.2; SM-A805N) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9; SM-G965F Build\/PPR1.180610.011;) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/106.0.5249.79 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SM-X200) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-T220) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SM-T870) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/90.0.4430.210 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-X906C Build\/QP1A.190711.020; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/80.0.3987.119 Mobile Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F916B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/101.0.4951.41 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 10; SM-F9160 Build\/QP1A.190711.020; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/76.0.3809.89 Mobile Safari\/537.36 T7\/12.4 SP-engine\/2.21.0 matrixstyle\/0 lite baiduboxapp\/5.1.6.10 (Baidu; P1 10) NABar\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SAMSUNG SM-F900U Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/94.0.3396.87 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SAMSUNG SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/16.2 Chrome\/92.0.4515.166 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SAMSUNG SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/17.0 Chrome\/96.0.4664.104 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/101.0.4951.61 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 11; SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/102.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SAMSUNG SM-F916B) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/17.0 Chrome\/96.0.4664.104 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SAMSUNG SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/17.0 Chrome\/96.0.4664.104 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SAMSUNG SM-F926U) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/18.0 Chrome\/99.0.4844.88 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F916B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/93.0.4577.75 Mobile Safari\/537.36 ABB\/3.0.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F916U) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/97.0.4692.98 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F926B Build\/SP1A.210812.016; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/104.0.5112.69 Mobile Safari\/537.36 EdgW\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F926B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F926U) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/99.0.4844.58 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F926U1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/103.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-F936B Build\/SP2A.220305.013; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/105.0.5195.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9.0; SAMSUNG SM-F900U Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/104.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 9.0; SAMSUNG SM-F900U Build\/PPR1.180610.011) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/105.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-X700) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/101.0.4951.41 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-X706B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/106.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-X900) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/107.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-X706B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/96.0.4664.104 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 13; SM-X806B Build\/TP1A.220624.014; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/108.0.5359.128 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 13; SM-X706B) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/110.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 13; SM-X706B Build\/TP1A.220624.014; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/114.0.5735.130 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 12; SM-P613) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/107.0.0.0 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 13; SM-P613 Build\/TP1A.220624.014; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/111.0.5563.58 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Samsung", + "user_agent": "Mozilla\/5.0 (Linux; Android 13; SAMSUNG SM-P613) AppleWebKit\/537.36 (KHTML, like Gecko) SamsungBrowser\/21.0 Chrome\/110.0.5481.154 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "SonyEricssonK800i\/R1AA Browser\/NetFront\/3.3 Profile\/MIDP-2.0 Configuration\/CLDC-1.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; es-ar; SonyEricssonE15a Build\/2.0.1.A.0.47) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.1-update1; pt-br; SonyEricssonU20a Build\/2.1.1.A.0.6) AppleWebKit\/530.17 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/530.17", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.3; en-au; SonyEricssonX10i Build\/3.0.1.G.0.75) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; ru-ru; SonyEricssonST18i Build\/4.0.2.A.0.62) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; hr-hr; SonyEricssonST15i Build\/4.0.2.A.0.62) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.4; sk-sk; SonyEricssonLT15i Build\/4.0.2.A.0.62) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; th-th; SonyEricssonST27i Build\/6.0.B.3.184) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 2.3.7; de-de; SonyEricssonST25i Build\/6.0.B.3.184) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; pt-br; Xperia Tablet S Build\/TID0092) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.0.3", + "Build": "TID0092", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; LT18i Build\/4.1.A.0.562) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; Sony Tablet S Build\/TISU0R0110) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; es-es; Sony Tablet S Build\/TISU0143) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-gb; SonyEricssonLT18i Build\/4.1.B.0.587) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; fr-ch; SonyEricssonSK17i Build\/4.1.B.0.587) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; SonyEricssonLT26i Build\/6.1.A.2.45) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; LT22i Build\/6.1.B.0.544) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; vi-vn; SonyEricssonLT22i Build\/6.1.B.0.544) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; ST23i Build\/11.0.A.5.5) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; ST23i Build\/11.0.A.2.10) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Mobile Safari\/535.19", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.4; LT28h Build\/6.1.E.3.7) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; SGPT13 Build\/TJDS0170) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; ja-jp; SonySO-03E Build\/10.1.E.0.265) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.1.2", + "Build": "10.1.E.0.265", + "Webkit": "534.30", + "Safari": "4.0" + } + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; LT26w Build\/6.2.B.1.96) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/29.0.1547.72 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; SGP321 Build\/10.3.1.A.0.33) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.58 Safari\/537.31", + "mobile": true, + "tablet": true, + "version": { + "Android": "4.2.2", + "Build": "10.3.1.A.0.33", + "Webkit": "537.31", + "Chrome": "26.0.1410.58" + } + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; C5303 Build\/12.1.A.1.205) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/36.0.1985.135 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; XL39h Build\/14.2.A.1.136) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; sv-se; C5503 Build\/10.1.1.A.1.273) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; C5502 Build\/10.1.1.A.1.310) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-cn; SonyL39t Build\/14.1.M.0.202) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; zh-cn; L39u Build\/14.1.n.0.63) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; zh-tw; M35c Build\/12.0.B.5.37) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; M35c Build\/12.0.B.2.42) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.90 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; zh-CN; M35t Build\/12.0.C.2.42) AppleWebKit\/534.31 (KHTML, like Gecko) UCBrowser\/9.3.2.349 U3\/0.8.0 Mobile Safari\/534.31", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; D6502 Build\/17.1.A.2.69) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; D6503 Build\/17.1.A.0.504) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; D6543 Build\/17.1.A.2.55) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2004 Build\/20.0.A.0.29) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-gb; D2005 Build\/20.0.A.1.12) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2104 Build\/20.0.B.0.84) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2105 Build\/20.0.B.0.74) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.170 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; pt-br; D2114 Build\/20.0.B.0.85) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2302 Build\/18.0.B.1.23) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; S50h Build\/18.0.b.1.23) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.6.3.413 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2303 Build\/18.0.C.1.13) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2305 Build\/18.0.A.1.30) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.138 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D2306 Build\/18.0.C.1.7) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D5303 Build\/19.0.1.A.0.207) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; D5306 Build\/19.1.A.0.264) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-CN; XM50h Build\/19.0.D.0.269) AppleWebKit\/533.1 (KHTML, like Gecko) Version\/4.0 UCBrowser\/9.7.6.428 U3\/0.8.0 Mobile Safari\/533.1", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; XM50t Build\/19.0.C.2.59) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; D5322 Build\/19.0.D.0.253) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.131", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; zh-cn; M51w Build\/14.2.A.1.146) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; M51w Build\/14.2.A.1.146) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/33.0.1750.136 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.1; D5102 Build\/18.2.A.0.9) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.1; D5103 Build\/18.1.A.0.11) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.92 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.1; D5106 Build\/18.1.A.0.11) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.3; en-gb; C6902 Build\/14.2.A.1.136) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30 GSA\/3.2.17.1009776.arm", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; es-es; C6943 Build\/14.1.G.2.257) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; C6943 Build\/14.3.A.0.681) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; SGP412 Build\/14.1.B.3.320) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1; en-us; SonySGP321 Build\/10.2.C.0.143) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.1.2; SGP351 Build\/10.1.1.A.1.307) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.3; SGP341 Build\/10.4.B.0.569) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SGP511 Build\/17.1.A.2.36) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SGP512 Build\/17.1.A.2.36) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.122 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; fr-ch; SGP311 Build\/10.1.C.0.344) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; SGP312 Build\/10.1.C.0.344) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; de-de; SGP521 Build\/17.1.A.2.69) AppleWebKit\/537.16 (KHTML, like Gecko) Version\/4.0 Safari\/537.16", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.4.2; zh-cn; SGP541 Build\/17.1.A.2.36) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; SGP551 Build\/17.1.A.2.72) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/34.0.1847.114 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "SonyEricssonU5i\/R2CA; Mozilla\/5.0 (SymbianOS\/9.4; U; Series60\/5.0 Profile\/MIDP-2.1 Configuration\/CLDC-1.1) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 Safari\/525", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "SonyEricssonU5i\/R2AA; Mozilla\/5.0 (SymbianOS\/9.4; U; Series60\/5.0 Profile\/MIDP-2.1 Configuration\/CLDC-1.1) AppleWebKit\/525 (KHTML, like Gecko) Version\/3.0 Safari\/525", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/4.0 (PDA; PalmOS\/sony\/model prmr\/Revision:1.1.54 (en)) NetFront\/3.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Opera\/9.80 (Linux mips; U; InettvBrowser\/2.2 (00014A;SonyDTV115;0002;0100) KDL40EX720; CC\/BEL; en) Presto\/2.7.61 Version\/11.00", + "mobile": false, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Opera\/9.80 (Linux armv7l; HbbTV\/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto\/2.12.362 Version\/12.11", + "mobile": false, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; es-ve; SonyST21a2 Build\/11.0.A.6.5) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.2; D2533 Build\/19.2.A.0.391) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/30.0.0.0 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.4.4; Xperia SP Build\/KTU84Q) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/41.0.2272.96 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla \/ 5.0 (Linux; Android 5.0.2; SOT31 Build \/ 28.0.D.6.71) AppleWebKit \/ 537.36 (KHTML, like Gecko) Chrome \/ 39.0.2171.93 Safari \/ 537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; E5823 Build\/32.0.A.4.11) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/46.0.2490.76 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.0; E2303 Build\/26.1.A.3.111) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.126 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; SGP771 Build\/32.4.A.1.54) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/68.0.3440.91 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; SOV34 Build\/41.3.C.0.297; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/65.0.3325.109 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; 601SO Build\/39.0.D.1.25; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/65.0.3325.109 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Sony", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.1.1; F8332 Build\/41.2.A.2.223) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.83 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Avant", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64; Trident\/7.0; Avant Browser; rv:11.0) like Gecko", + "mobile": false, + "tablet": false + }, + { + "vendor": "Avant", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64; Avant TriCore) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/30.0.1599.101 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Avant", + "user_agent": "Mozilla\/5.0 (Windows NT 5.1; rv:27.0; Avant TriCore) Gecko\/20100101 Firefox\/27.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (Nintendo WiiU) AppleWebKit\/536.28 (KHTML, like Gecko) NX\/3.0.3.12.14 NintendoBrowser\/3.1.1.9577.EU", + "mobile": false, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (Nintendo WiiU) AppleWebKit\/534.52 (KHTML, like Gecko) NX\/{Version No} NintendoBrowser\/{Version No}.US", + "mobile": false, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (Nintendo 3DS; U; ; en) Version\/1.7567.US", + "mobile": true, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (Nintendo 3DS; U; ; en) Version\/1.7498.US", + "mobile": true, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (PLAYSTATION 3 4.21) AppleWebKit\/531.22.8 (KHTML, like Gecko)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Console", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident\/5.0; Xbox)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.0.0; K10 G1 Build\/O00623; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/58.0.3029.125 Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Linux; Android 8.1.0; GAAMII G1 Build\/O11019; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/61.0.3163.98 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 7.1.2; zh-cn; Z999 Build\/N2G47H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/57.0.2987.132 MQQBrowser\/8.4 Mobile Safari\/537.36", + "mobile": true, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/53.0.2785.148 Safari\/537.36 Vivaldi\/1.4.589.41", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident\/4.0; SV1; [eburo v4.0]; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.3; .NET4.0C; .NET4.0E)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit\/600.1.25 (KHTML, like Gecko) Version\/8.0 Safari\/600.1.25", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/38.0.2125.111 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1) AppleWebKit\/537.36 (KHTML, like Gecko) Iron\/37.0.2000.0 Chrome\/37.0.2000.0 Safari\/537.36", + "mobile": false, + "tablet": false, + "version": { + "Iron": "37.0.2000.0" + } + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; Linux i686) AppleWebKit\/537.36 (KHTML, like Gecko) Ubuntu Chromium\/32.0.1700.102 Chrome\/32.0.1700.102 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko\/20100101 Firefox\/24.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko\/20100101 Firefox\/18.0 AlexaToolbar\/psPCtGhf-2.2", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko\/20100101 Firefox\/22.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; Linux ppc; rv:17.0) Gecko\/20130626 Firefox\/17.0 Iceweasel\/17.0.7", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; Linux) AppleWebKit\/535.22+ Midori\/0.4", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Macintosh; U; Intel Mac OS X; en-us) AppleWebKit\/535+ (KHTML, like Gecko) Version\/5.0 Safari\/535.20+ Midori\/0.4", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.20 Safari\/537.36 OPR\/15.0.1147.18 (Edition Next)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.2) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.94 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 5.2; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.94 Safari\/537.36", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 5.2; WOW64; rv:21.0) Gecko\/20100101 Firefox\/21.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Opera\/9.80 (Windows NT 5.2; WOW64) Presto\/2.12.388 Version\/12.14", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko\/20100101 Firefox\/19.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (X11; FreeBSD amd64; rv:14.0) Gecko\/20100101 Firefox\/14.0.1", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Win64; x64; Trident\/6.0; Touch; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Tablet PC 2.0; MASMJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident\/6.0; MANMJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident\/6.0; MASMJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident\/6.0; Touch; MASMJS)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Opera\/9.80 (Windows NT 6.2; WOW64; MRA 8.0 (build 5784)) Presto\/2.12.388 Version\/12.11", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident\/6.0)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.3; Trident\/7.0; rv 11.0) like Gecko", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Windows NT 6.3; WOW64; Trident\/7.0; Touch; rv:11.0) like Gecko", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Mozilla\/5.0 (Unknown; Linux armv7l) AppleWebKit\/537.1+ (KHTML, like Gecko) Safari\/537.1+ HbbTV\/1.1.1 ( ;LGE ;NetCast 4.0 ;03.20.30 ;1.0M ;)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "HbbTV\/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Other", + "user_agent": "Opera\/9.80 (Linux armv7l; HbbTV\/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto\/2.12.362 Version\/12.11", + "mobile": false, + "tablet": false + }, + { + "vendor": "TV", + "user_agent": "Mozilla\/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit\/538.1 (KHTML, like Gecko) SamsungBrowser\/1.0 TV Safari\/538.1", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:38.9) Gecko\/20100101 Goanna\/2.0 Firefox\/38.9 PaleMoon\/26.0.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:2.0) Gecko\/20100101 Goanna\/20160121 PaleMoon\/26.0.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:38.9) Gecko\/20100101 Goanna\/2.0 Firefox\/38.9 PaleMoon\/26.1.1", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko\/31.0 Firefox\/31.0 SailfishBrowser\/1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Maemo; Linux; U; Jolla; Sailfish; Tablet; rv:31.0) Gecko\/31.0 Firefox\/31.0 SailfishBrowser\/1.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Sailfish 3.0; Mobile; rv:38.0) Gecko\/38.0 Firefox\/38.0 SailfishBrowser\/1.0", + "mobile": true, + "tablet": false, + "version": { + "Sailfish": "3.0", + "SailfishBrowser": "1.0", + "Gecko": "38.0" + } + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Sailfish 3.0; Tablet; rv:38.0) Gecko\/38.0 Firefox\/38.0 SailfishBrowser\/1.0", + "mobile": true, + "tablet": true, + "version": { + "Sailfish": "3.0", + "SailfishBrowser": "1.0", + "Gecko": "38.0" + } + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Mobile; rv:26.0) Gecko\/26.0 Firefox\/26.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Tablet; rv:26.0) Gecko\/26.0 Firefox\/26.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; CT1020W Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/28.0.1500.94 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.2.2; M6pro Build\/JDQ39) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.141 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "MobileSafari\/9537.53 CFNetwork\/672.1.13 Darwin\/13.1.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Appcelerator Titanium\/3.2.2.GA (iPod touch\/6.1.6; iPhone OS; en_US;)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera Coast\/3.0.3.78307 CFNetwork\/672.1.15 Darwin\/14.0.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; ALUMIUM10 Build\/IML74K) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0.1700.99 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.1; en-us; JY-G3 Build\/JOP40D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; hu-hu; M758A Build\/JRO03C) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; en-us; EVOTAB Build\/IMM76I) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Java\/1.6.0_22", + "mobile": false, + "tablet": false, + "version": { + "Java": "1.6.0_22" + } + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Series 60; Opera Mini\/6.5.29260\/29.3417; U; ru) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Android; Opera Mini\/6.5.27452\/29.3417; U; ru) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (iPhone; Opera Mini\/7.1.32694\/27.1407; U; en) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\/537.17 (KHTML, like Gecko) Chrome\/24.0.1312.60 Safari\/537.17 OPR\/14.0.1025.52315", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit\/533.17.9 (KHTML, like Gecko) Version\/5.0.2 Mobile\/8H7 Safari\/6533.18.5", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Android 2.3.7; Linux; Opera Mobi\/46154) Presto\/2.11.355 Version\/12.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (iPad; CPU OS 6_1 like Mac OS X) AppleWebKit\/536.26 (KHTML, like Gecko) Version\/6.0 Mobile\/10B141 Safari\/8536.25", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.2; en-us; sdk Build\/MASTER) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2; en-us; sdk Build\/JB_MR1) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Android; Mobile; rv:18.0) Gecko\/18.0 Firefox\/18.0", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Windows NT 6.1) AppleWebKit\/535.12 (KHTML, like Gecko) Maxthon\/3.0 Chrome\/18.0.966.0 Safari\/535.12", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Windows NT 5.1; U; Edition Yx; ru) Presto\/2.10.289 Version\/12.02", + "mobile": false, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows Phone 6.5.3.5)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "PalmCentro\/v0001 Mozilla\/4.0 (compatible; MSIE 6.0; Windows 98; PalmSource\/Palm-D061; Blazer\/4.5) 16;320x320", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; Microsoft; XDeviceEmulator)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; MAL; N880E; China Telecom)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Series 60; Opera Mini\/7.0.29482\/28.2859; U; ru) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (S60; SymbOS; Opera Mobi\/SYB-1202242143; U; en-GB) Presto\/2.10.254 Version\/12.00", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.3; en-au; 97D Build\/IML74K) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Android; Opera Mini\/7.0.29952\/28.2647; U; ru) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Android; Opera Mini\/6.1.25375\/28.2555; U; en) Presto\/2.8.119 Version\/11.10", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Mac OS X; Opera Tablet\/35779; U; en) Presto\/2.10.254 Version\/12.00", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Android; Tablet; rv:10.0.4) Gecko\/10.0.4 Firefox\/10.0.4 Fennec\/10.0.4", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Android; Tablet; rv:18.0) Gecko\/18.0 Firefox\/18.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Linux armv7l; Maemo; Opera Mobi\/14; U; en) Presto\/2.9.201 Version\/11.50", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Opera\/9.80 (Android 2.2.1; Linux; Opera Mobi\/ADR-1207201819; U; en) Presto\/2.10.254 Version\/12.00", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; en-us; sdk Build\/JRO03E) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30", + "mobile": true, + "tablet": false + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; Endeavour 1010 Build\/ONDA_MID) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; de-de; Tablet-PC-4 Build\/ICS.g08refem618.20121102) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Generic", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.2.2; de-de; Tagi Tab S10 Build\/8089) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Bot", + "user_agent": "Mozilla\/5.0 (compatible; Googlebot\/2.1; +http:\/\/www.google.com\/bot.html)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "grub-client-1.5.3; (grub-client-1.5.3; Crawl your own stuff with http:\/\/grub.org)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Googlebot-Image\/1.0", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Python-urllib\/2.5", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "facebookexternalhit\/1.0 (+http:\/\/www.facebook.com\/externalhit_uatext.php)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "AdsBot-Google (+http:\/\/www.google.com\/adsbot.html)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "AdsBot-Google-Mobile (+http:\/\/www.google.com\/mobile\/adsbot.html) Mozilla (iPhone; U; CPU iPhone OS 3 0 like Mac OS X) AppleWebKit (KHTML, like Gecko) Mobile Safari", + "mobile": true, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Mozilla\/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit\/534.16 (KHTML, like Gecko, Google Keyword Suggestion) Chrome\/10.0.648.127 Safari\/534.16", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Facebot", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/60.0.3112.113 Safari\/537.36 (+https:\/\/whatis.contentkingapp.com)", + "mobile": false, + "tablet": false + }, + { + "vendor": "Bot", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0;) AppleWebKit\/537.36 (KHTML, like Gecko) Mobile Safari\/537.36 (compatible; AspiegelBot)", + "mobile": true, + "tablet": false + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1.1; QTAQZ3 Build\/LMY47V) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; QTAIR7 Build\/LMY47D) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0 (Linux; Android 5.1; QTAIR7 Build\/LMY47D; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/58.0.3029.83 Safari\/537.36 [Pinterest\/Android]", + "mobile": true, + "tablet": true + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; QTASUN1 Build\/MMB29M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/56.0.2924.87 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0 (Linux; Android 7.0; QTASUN1 Build\/NRD90M) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/60.0.3112.116 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Verizon", + "user_agent": "Mozilla\/5.0(LInux;Android 5.1.1; QTAQTZ3 Build\/LMY47V) AppleWebKit\/537.36(KHTML, like Gecko) Chrome\/59.0.3071.125 Safari\/537.36", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vodafone", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 3.2; hu-hu; SmartTab10-MSM8260-V02d-Dec022011-Vodafone-HU) AppleWebKit\/534.13 (KHTML, like Gecko) Version\/4.0", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vodafone", + "user_agent": "Mozilla\/5.0 (Linux; Android 4.0.3; SmartTabII10 Build\/IML74K) AppleWebKit\/535.19 (KHTML, like Gecko) Chrome\/18.0.1025.166 Safari\/535.19", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vodafone", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.1.1; fr-fr; SmartTAB 1002 Build\/JRO03H) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vodafone", + "user_agent": "Mozilla\/5.0 (Linux; U; Android 4.0.4; de-de, SmartTabII7 Build\/A2107A_A404_107_055_130124_VODA) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Safari\/534.30", + "mobile": true, + "tablet": true + }, + { + "vendor": "Vodafone", + "user_agent": "Mozilla\/5.0 (Linux; Android 6.0.1; VFD 1400 Build\/MMB29M; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/68.0.3440.91 Safari\/537.36", + "mobile": true, + "tablet": true + } + ] +} \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/COPYING b/lib/vendor/mustangostang/spyc/COPYING new file mode 100644 index 0000000000..8e7ddbcf6b --- /dev/null +++ b/lib/vendor/mustangostang/spyc/COPYING @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2011 Vladimir Andersen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/README.md b/lib/vendor/mustangostang/spyc/README.md new file mode 100644 index 0000000000..1ebbdc556a --- /dev/null +++ b/lib/vendor/mustangostang/spyc/README.md @@ -0,0 +1,30 @@ +**Spyc** is a YAML loader/dumper written in pure PHP. Given a YAML document, Spyc will return an array that +you can use however you see fit. Given an array, Spyc will return a string which contains a YAML document +built from your data. + +**YAML** is an amazingly human friendly and strikingly versatile data serialization language which can be used +for log files, config files, custom protocols, the works. For more information, see http://www.yaml.org. + +Spyc supports YAML 1.0 specification. + +## Using Spyc + +Using Spyc is trivial: + +```php + + * @author Chris Wanstrath + * @link https://github.com/mustangostang/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +if (!function_exists('spyc_dump')) { + /** + * Dumps array to YAML. + * @param array $data Array. + * @return string + */ + function spyc_dump ($data) { + return Spyc::YAMLDump($data, false, false, true); + } +} + +if (!class_exists('Spyc')) { + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_empty_hash_as_object = false; + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->_loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->_load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + * @param array set options + */ + public static function YAMLLoad($input, $options = []) { + $Spyc = new Spyc; + foreach ($options as $key => $value) { + if (property_exists($Spyc, $key)) { + $Spyc->$key = $value; + } + } + return $Spyc->_load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + * @param array set options + */ + public static function YAMLLoadString($input, $options = []) { + $Spyc = new Spyc; + foreach ($options as $key => $value) { + if (property_exists($Spyc, $key)) { + $Spyc->$key = $value; + } + } + return $Spyc->_loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array|\stdClass $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + * @param bool $no_opening_dashes Do not start YAML file with "---\n" + */ + public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { + $spyc = new Spyc; + return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = ""; + if (!$no_opening_dashes) $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if(is_object($value)) $value = (array)$value; + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if ($value === "") $value = '""'; + if (self::isTranslationWord($value)) { + $value = $this->_doLiteralBlock($value, $indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = $value ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) { + $newValue = $exploded[0]; + unset($exploded[0]); + } + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $line = trim($line); + if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) { + $line = substr($line, 1, -1); + } + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + if (is_numeric($value) && is_string($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + + private function isTrueWord($value) { + $words = self::getTranslations(array('true', 'on', 'yes', 'y')); + return in_array($value, $words, true); + } + + private function isFalseWord($value) { + $words = self::getTranslations(array('false', 'off', 'no', 'n')); + return in_array($value, $words, true); + } + + private function isNullWord($value) { + $words = self::getTranslations(array('null', '~')); + return in_array($value, $words, true); + } + + private function isTranslationWord($value) { + return ( + self::isTrueWord($value) || + self::isFalseWord($value) || + self::isNullWord($value) + ); + } + + /** + * Coerce a string into a native type + * Reference: http://yaml.org/type/bool.html + * TODO: Use only words from the YAML spec. + * @access private + * @param $value The value to coerce + */ + private function coerceValue(&$value) { + if (self::isTrueWord($value)) { + $value = true; + } else if (self::isFalseWord($value)) { + $value = false; + } else if (self::isNullWord($value)) { + $value = null; + } + } + + /** + * Given a set of words, perform the appropriate translations on them to + * match the YAML 1.1 specification for type coercing. + * @param $words The words to translate + * @access private + */ + private static function getTranslations(array $words) { + $result = array(); + foreach ($words as $i) { + $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); + } + return $result; + } + +// LOADING FUNCTIONS + + private function _load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function _loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ("\n", $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= ' '.$this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + // Strip out comments + if (strpos ($line, '#')) { + $line = preg_replace('/\s*#([^"\']+)$/','',$line); + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + $input = file_get_contents($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) { + return $this->returnMappedSequence($line); + } + + if ($this->startsMappedValue($line)) { + return $this->returnMappedValue($line); + } + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return ""; + + if ($this->setting_empty_hash_as_object && $value === '{}') { + return new stdClass(); + } + + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) { + $value = str_replace('\n', "\n", $value); + if ($first_character == "'") + return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\'')); + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\'')); + } + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { + // Hexadecimal value. + return hexdec($value); + } + + $this->coerceValue($value); + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + $saved_empties = array(); + + // Check for empty strings + $regex = '/("")|(\'\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_empties = $strings[0]; + $inline = preg_replace($regex,'YAMLEmpty',$inline); + } + unset($regex); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + // echo $inline; + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(',',$inline); + $explode = array_map('trim', $explode); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + + // Re-add the empties + if (!empty($saved_empties)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLEmpty') !== false) { + $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLEmpty') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line || !is_scalar($line)) return false; + if (substr($line, 0, 2) != '- ') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function checkKeysInValue($value) { + if (strchr('[{"\'', $value[0]) === false) { + if (strchr($value, ': ') !== false) { + throw new Exception('Too many keys: '.$value); + } + } + } + + private function returnMappedValue ($line) { + $this->checkKeysInValue($line); + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ': ')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(': ', $line); + $key = trim(array_shift($explode)); + $value = trim(implode(': ', $explode)); + $this->checkKeysInValue($value); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + if ($this->isArrayElement($value)) { + $value = $this->returnArrayElement($value); + } + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} +} + +// Enable use of Spyc from command line +// The syntax is the following: php Spyc.php spyc.yaml + +do { + if (PHP_SAPI != 'cli') break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break; + $file = $argv[1]; + echo json_encode (spyc_load_file ($file)); +} while (0); diff --git a/lib/vendor/mustangostang/spyc/composer.json b/lib/vendor/mustangostang/spyc/composer.json new file mode 100644 index 0000000000..e5ab776848 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/composer.json @@ -0,0 +1,30 @@ +{ + "name": "mustangostang/spyc", + "description": "A simple YAML loader/dumper class for PHP", + "type": "library", + "keywords": [ + "spyc", + "yaml", + "yml" + ], + "homepage": "https://github.com/mustangostang/spyc/", + "authors" : [{ + "name": "mustangostang", + "email": "vlad.andersen@gmail.com" + }], + "license": "MIT", + "require": { + "php": ">=5.3.1" + }, + "autoload": { + "files": [ "Spyc.php" ] + }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + } +} diff --git a/lib/vendor/mustangostang/spyc/examples/yaml-dump.php b/lib/vendor/mustangostang/spyc/examples/yaml-dump.php new file mode 100644 index 0000000000..9d2160aaf8 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/examples/yaml-dump.php @@ -0,0 +1,25 @@ + 'A sequence','second' => 'of mapped values'); +$array['Mapped'] = array('A sequence','which is mapped'); +$array['A Note'] = 'What if your text is too long?'; +$array['Another Note'] = 'If that is the case, the dumper will probably fold your text by using a block. Kinda like this.'; +$array['The trick?'] = 'The trick is that we overrode the default indent, 2, to 4 and the default wordwrap, 40, to 60.'; +$array['Old Dog'] = "And if you want\n to preserve line breaks, \ngo ahead!"; +$array['key:withcolon'] = "Should support this to"; + +$yaml = Spyc::YAMLDump($array,4,60); diff --git a/lib/vendor/mustangostang/spyc/examples/yaml-load.php b/lib/vendor/mustangostang/spyc/examples/yaml-load.php new file mode 100644 index 0000000000..9e457e1e15 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/examples/yaml-load.php @@ -0,0 +1,21 @@ +spyc.yaml loaded into PHP:
      '; +print_r($array); +echo ''; + + +echo '
      YAML Data dumped back:
      '; +echo Spyc::YAMLDump($array); +echo '
      '; diff --git a/lib/vendor/mustangostang/spyc/php4/5to4.php b/lib/vendor/mustangostang/spyc/php4/5to4.php new file mode 100644 index 0000000000..5a48694f01 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/php4/5to4.php @@ -0,0 +1,17 @@ +', $code); + $f = fopen ($dest, 'w'); + fwrite($f, $code); + fclose ($f); + print "Written to $dest.\n"; +} \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/php4/spyc.php4 b/lib/vendor/mustangostang/spyc/php4/spyc.php4 new file mode 100644 index 0000000000..73f08cc079 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/php4/spyc.php4 @@ -0,0 +1,1023 @@ + + * @author Chris Wanstrath + * @link http://code.google.com/p/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + var $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + var $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + var $_dumpIndent; + var $_dumpWordWrap; + var $_containsGroupAnchor = false; + var $_containsGroupAlias = false; + var $path; + var $result; + var $LiteralPlaceHolder = '___YAML_Literal_Block___'; + var $SavedGroups = array(); + var $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + var $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + var $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + function load ($input) { + return $this->__loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + function loadFile ($file) { + return $this->__load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->__load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + */ + function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->__loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + function YAMLDump($array,$indent = false,$wordwrap = false) { + $spyc = new Spyc; + return $spyc->dump($array,$indent,$wordwrap); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + function dump($array,$indent = false,$wordwrap = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $first_key = key($array); + + $previous_key = -1; + foreach ($array as $key => $value) { + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) { + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + $first_key = key($array); + foreach ($array as $key => $value) { + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':')) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + if (is_bool($value)) { + $value = ($value) ? "true" : "false"; + } + } + + if ($value === array()) $value = '[ ]'; + + $spaces = str_repeat(' ',$indent); + + if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; } + $string = $spaces.$key.': '.$value."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + function _doLiteralBlock($value,$indent) { + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $newValue .= "\n" . $spaces . trim($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + +// LOADING FUNCTIONS + + function __load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + function __loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ('', $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = $this->stripIndent($line, $this->indent); + if ($this->isComment($line)) continue; + if ($this->isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = $this->startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= $this->LiteralPlaceHolder; + + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle); + } + $i--; + } + + while (++$i < $cnt && $this->greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + + + if (strpos ($line, '#')) { + if (strpos ($line, '"') === false && strpos ($line, "'") === false) + $line = preg_replace('/\s+#(.+)$/','',$line); + } + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + return file($input); + + return $this->loadFromString($input); + } + + function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + + if (!$line) return array(); + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + function _toType($value) { + if ($value === '') return null; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + + if (strpos($value, ' #') !== false) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) { + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if (in_array($value, + array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { + return true; + } + + if (in_array(strtolower($value), + array('false', 'off', '-', 'no', 'n'))) { + return false; + } + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (trim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(', ',$inline); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + return $explode; + } + + function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + function addLiteralLine ($literalBlock, $line, $literalBlockStyle) { + $line = $this->stripIndent($line); + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + function isEmpty ($line) { + return (trim ($line) === ''); + } + + + function isArrayElement ($line) { + if (!$line) return false; + if ($line[0] != '-') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + function isHashElement ($line) { + return strpos($line, ':'); + } + + function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + function startsMappedSequence ($line) { + return ($line[0] == '-' && substr ($line, -1, 1) == ':'); + } + + function returnMappedSequence ($line) { + $array = array(); + $key = $this->unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + function returnMappedValue ($line) { + $array = array(); + $key = $this->unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + function returnPlainArray ($line) { + return $this->_toType($line); + } + + function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ':')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(':',$line); + $key = trim($explode[0]); + array_shift($explode); + $value = trim(implode(':',$explode)); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + $array[] = $value; + return $array; + } + + + function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} + +// Enable use of Spyc from command line +// The syntax is the following: php spyc.php spyc.yaml + +define ('SPYC_FROM_COMMAND_LINE', false); + +do { + if (!SPYC_FROM_COMMAND_LINE) break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; + $file = $argv[1]; + printf ("Spyc loading file: %s\n", $file); + print_r (spyc_load_file ($file)); +} while (0); \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/php4/test.php4 b/lib/vendor/mustangostang/spyc/php4/test.php4 new file mode 100644 index 0000000000..315f5019d8 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/php4/test.php4 @@ -0,0 +1,162 @@ + "1.5ghz", "ram" => "1 gig", + "os" => "os x 10.4.1")) + die('Sequence 4 failed'); + +# Mapped sequence +if ($yaml['domains'] != array("yaml.org", "php.net")) + die("Key: 'domains' failed"); + +# A sequence like this. +if ($yaml[5] != array("program" => "Adium", "platform" => "OS X", + "type" => "Chat Client")) + die('Sequence 5 failed'); + +# A folded block as a mapped value +if ($yaml['no time'] != "There isn't any time for your tricks!\nDo you understand?") + die("Key: 'no time' failed"); + +# A literal block as a mapped value +if ($yaml['some time'] != "There is nothing but time\nfor your tricks.") + die("Key: 'some time' failed"); + +# Crazy combinations +if ($yaml['databases'] != array( array("name" => "spartan", "notes" => + array( "Needs to be backed up", + "Needs to be normalized" ), + "type" => "mysql" ))) + die("Key: 'databases' failed"); + +# You can be a bit tricky +if ($yaml["if: you'd"] != "like") + die("Key: 'if: you\'d' failed"); + +# Inline sequences +if ($yaml[6] != array("One", "Two", "Three", "Four")) + die("Sequence 6 failed"); + +# Nested Inline Sequences +if ($yaml[7] != array("One", array("Two", "And", "Three"), "Four", "Five")) + die("Sequence 7 failed"); + +# Nested Nested Inline Sequences +if ($yaml[8] != array( "This", array("Is", "Getting", array("Ridiculous", "Guys")), + "Seriously", array("Show", "Mercy"))) + die("Sequence 8 failed"); + +# Inline mappings +if ($yaml[9] != array("name" => "chris", "age" => "young", "brand" => "lucky strike")) + die("Sequence 9 failed"); + +# Nested inline mappings +if ($yaml[10] != array("name" => "mark", "age" => "older than chris", + "brand" => array("marlboro", "lucky strike"))) + die("Sequence 10 failed"); + +# References -- they're shaky, but functional +if ($yaml['dynamic languages'] != array('Perl', 'Python', 'PHP', 'Ruby')) + die("Key: 'dynamic languages' failed"); + +if ($yaml['compiled languages'] != array('C/C++', 'Java')) + die("Key: 'compiled languages' failed"); + +if ($yaml['all languages'] != array( + array('Perl', 'Python', 'PHP', 'Ruby'), + array('C/C++', 'Java') + )) + die("Key: 'all languages' failed"); + +# Added in .2.2: Escaped quotes +if ($yaml[11] != "you know, this shouldn't work. but it does.") + die("Sequence 11 failed."); + +if ($yaml[12] != "that's my value.") + die("Sequence 12 failed."); + +if ($yaml[13] != "again, that's my value.") + die("Sequence 13 failed."); + +if ($yaml[14] != "here's to \"quotes\", boss.") + die("Sequence 14 failed."); + +if ($yaml[15] != array( 'name' => "Foo, Bar's", 'age' => 20)) + die("Sequence 15 failed."); + +if ($yaml[16] != array( 0 => "a", 1 => array (0 => 1, 1 => 2), 2 => "b")) + die("Sequence 16 failed."); + +if ($yaml['endloop'] != "Does this line in the end indeed make Spyc go to an infinite loop?") + die("[endloop] failed."); + + +print "spyc.yaml parsed correctly\n"; + +?> \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/phpunit.xml b/lib/vendor/mustangostang/spyc/phpunit.xml new file mode 100644 index 0000000000..a6151af8e8 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/phpunit.xml @@ -0,0 +1,8 @@ + + + + + tests/ + + + diff --git a/lib/vendor/mustangostang/spyc/spyc.yaml b/lib/vendor/mustangostang/spyc/spyc.yaml new file mode 100644 index 0000000000..489f28c9fb --- /dev/null +++ b/lib/vendor/mustangostang/spyc/spyc.yaml @@ -0,0 +1,219 @@ +# +# S P Y C +# a simple php yaml class +# +# authors: [vlad andersen (vlad.andersen@gmail.com), chris wanstrath (chris@ozmm.org)] +# websites: [http://www.yaml.org, http://spyc.sourceforge.net/] +# license: [MIT License, http://www.opensource.org/licenses/mit-license.php] +# copyright: (c) 2005-2006 Chris Wanstrath, 2006-2014 Vlad Andersen +# +# spyc.yaml - A file containing the YAML that Spyc understands. + +--- + +# Mappings - with proper types +String: Anyone's name, really. +Int: 13 +BadHex: f0xf3 +Hex: 0xf3 +True: true +False: false +Zero: 0 +Null: NULL +NotNull: 'null' +NotTrue: 'y' +NotBoolTrue: 'true' +NotInt: '5' +Float: 5.34 +Negative: -90 +SmallFloat: 0.7 +NewLine: \n +QuotedNewLine: "\n" + +# A sequence +- PHP Class +- Basic YAML Loader +- Very Basic YAML Dumper + +# A sequence of a sequence +- + - YAML is so easy to learn. + - Your config files will never be the same. + +# Sequence of mappings +- + cpu: 1.5ghz + ram: 1 gig + os : os x 10.4.1 + +# Mapped sequence +domains: + - yaml.org + - php.net + +# A sequence like this. +- program: Adium + platform: OS X + type: Chat Client + +# A folded block as a mapped value +no time: > + There isn't any time + for your tricks! + + Do you understand? + +# A literal block as a mapped value +some time: | + There is nothing but time + for your tricks. + +# Crazy combinations +databases: + - name: spartan + notes: + - Needs to be backed up + - Needs to be normalized + type: mysql + +# You can be a bit tricky +"if: you'd": like + +# Inline sequences +- [One, Two, Three, Four] + +# Nested Inline Sequences +- [One, [Two, And, Three], Four, Five] + +# Nested Nested Inline Sequences +- [This, [Is, Getting, [Ridiculous, Guys]], Seriously, [Show, Mercy]] + +# Inline mappings +- {name: chris, age: young, brand: lucky strike} + +# Nested inline mappings +- {name: mark, age: older than chris, brand: [marlboro, lucky strike]} + +# References -- they're shaky, but functional +dynamic languages: &DLANGS + - Perl + - Python + - PHP + - Ruby +compiled languages: &CLANGS + - C/C++ + - Java +all languages: + - *DLANGS + - *CLANGS + +# Added in .2.2: Escaped quotes +- you know, this shouldn't work. but it does. +- 'that''s my value.' +- 'again, that\'s my value.' +- "here's to \"quotes\", boss." + +# added in .2.3 +- {name: "Foo, Bar's", age: 20} + +# Added in .2.4: bug [ 1418193 ] Quote Values in Nested Arrays +- [a, ['1', "2"], b] + +# Add in .5.2: Quoted new line values. +- "First line\nSecond line\nThird line" + +# Added in .2.4: malformed YAML +all + javascripts: [dom1.js, dom.js] + +# Added in .2 +1040: Ooo, a numeric key! # And working comments? Wow! Colons in comments: a menace (0.3). + +hash_1: Hash #and a comment +hash_2: "Hash #and a comment" +"hash#3": "Hash (#) can appear in key too" + +float_test: 1.0 +float_test_with_quotes: '1.0' +float_inverse_test: 001 + +a_really_large_number: 115792089237316195423570985008687907853269984665640564039457584007913129639936 # 2^256 + +int array: [ 1, 2, 3 ] + +array on several lines: + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] + +morelesskey: "" + +array_of_zero: [0] +sophisticated_array_of_zero: {rx: {tx: [0]} } + +switches: + - { row: 0, col: 0, func: {tx: [0, 1]} } + +empty_sequence: [ ] +empty_hash: { } + +special_characters: "[{]]{{]]" + +asterisks: "*" + +empty_key: + : + key: value + +trailing_colon: "foo:" + +multiline_items: + - type: SomeItem + values: [blah, blah, blah, + blah] + ints: [2, 54, 12, + 2143] + +many_lines: | + A quick + fox + + + jumped + over + + + + + + a lazy + + + + dog + + +werte: + 1: nummer 1 + 0: Stunde 0 + +noindent_records: +- record1: value1 +- record2: value2 + +"a:1": [1000] +"a:2": + - 2000 +a:3: [3000] + +complex_unquoted_key: + a:b:''test': value + +array with commas: + ["0","1"] + +invoice: ["Something", "", '', "Something else"] +quotes: ['Something', "Nothing", 'Anything', "Thing"] + +# [Endloop] +endloop: | + Does this line in the end indeed make Spyc go to an infinite loop? diff --git a/lib/vendor/mustangostang/spyc/tests/DumpTest.php b/lib/vendor/mustangostang/spyc/tests/DumpTest.php new file mode 100644 index 0000000000..ceb5c8e5b1 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/DumpTest.php @@ -0,0 +1,194 @@ +files_to_test = array (__DIR__.'/../spyc.yaml', 'failing1.yaml', 'indent_1.yaml', 'quotes.yaml'); + } + + public function testShortSyntax() { + $dump = spyc_dump(array ('item1', 'item2', 'item3')); + $awaiting = "- item1\n- item2\n- item3\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDump() { + foreach ($this->files_to_test as $file) { + $yaml = spyc_load(file_get_contents($file)); + $dump = Spyc::YAMLDump ($yaml); + $yaml_after_dump = Spyc::YAMLLoad ($dump); + $this->assertEquals ($yaml, $yaml_after_dump); + } + } + + public function testDumpWithQuotes() { + $Spyc = new Spyc(); + $Spyc->setting_dump_force_quotes = true; + foreach ($this->files_to_test as $file) { + $yaml = $Spyc->load(file_get_contents($file)); + $dump = $Spyc->dump ($yaml); + $yaml_after_dump = Spyc::YAMLLoad ($dump); + $this->assertEquals ($yaml, $yaml_after_dump); + } + } + + public function testDumpArrays() { + $dump = Spyc::YAMLDump(array ('item1', 'item2', 'item3')); + $awaiting = "---\n- item1\n- item2\n- item3\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testNull() { + $dump = Spyc::YAMLDump(array('a' => 1, 'b' => null, 'c' => 3)); + $awaiting = "---\na: 1\nb: null\nc: 3\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testNext() { + $array = array("aaa", "bbb", "ccc"); + #set arrays internal pointer to next element + next($array); + $dump = Spyc::YAMLDump($array); + $awaiting = "---\n- aaa\n- bbb\n- ccc\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpingMixedArrays() { + $array = array(); + $array[] = 'Sequence item'; + $array['The Key'] = 'Mapped value'; + $array[] = array('A sequence','of a sequence'); + $array[] = array('first' => 'A sequence','second' => 'of mapped values'); + $array['Mapped'] = array('A sequence','which is mapped'); + $array['A Note'] = 'What if your text is too long?'; + $array['Another Note'] = 'If that is the case, the dumper will probably fold your text by using a block. Kinda like this.'; + $array['The trick?'] = 'The trick is that we overrode the default indent, 2, to 4 and the default wordwrap, 40, to 60.'; + $array['Old Dog'] = "And if you want\n to preserve line breaks, \ngo ahead!"; + $array['key:withcolon'] = "Should support this to"; + + $yaml = Spyc::YAMLDump($array,4,60); + } + + public function testMixed() { + $dump = Spyc::YAMLDump(array(0 => 1, 'b' => 2, 1 => 3)); + $awaiting = "---\n0: 1\nb: 2\n1: 3\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpNumerics() { + $dump = Spyc::YAMLDump(array ('404', '405', '500')); + $awaiting = "---\n- \"404\"\n- \"405\"\n- \"500\"\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpAsterisks() { + $dump = Spyc::YAMLDump(array ('*')); + $awaiting = "---\n- '*'\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpAmpersands() { + $dump = Spyc::YAMLDump(array ('some' => '&foo')); + $awaiting = "---\nsome: '&foo'\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpExclamations() { + $dump = Spyc::YAMLDump(array ('some' => '!foo')); + $awaiting = "---\nsome: '!foo'\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpExclamations2() { + $dump = Spyc::YAMLDump(array ('some' => 'foo!')); + $awaiting = "---\nsome: foo!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpApostrophes() { + $dump = Spyc::YAMLDump(array ('some' => "'Biz' pimpt bedrijventerreinen")); + $awaiting = "---\nsome: \"'Biz' pimpt bedrijventerreinen\"\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testDumpNumericHashes() { + $dump = Spyc::YAMLDump(array ("titel"=> array("0" => "", 1 => "Dr.", 5 => "Prof.", 6 => "Prof. Dr."))); + $awaiting = "---\ntitel:\n 0: \"\"\n 1: Dr.\n 5: Prof.\n 6: Prof. Dr.\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testEmpty() { + $dump = Spyc::YAMLDump(array("foo" => array())); + $awaiting = "---\nfoo: [ ]\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testHashesInKeys() { + $dump = Spyc::YAMLDump(array ('#color' => '#ffffff')); + $awaiting = "---\n\"#color\": '#ffffff'\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testParagraph() { + $dump = Spyc::YAMLDump(array ('key' => "|\n value")); + $awaiting = "---\nkey: |\n value\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testParagraphTwo() { + $dump = Spyc::YAMLDump(array ('key' => 'Congrats, pimpt bedrijventerreinen pimpt bedrijventerreinen pimpt bedrijventerreinen!')); + $awaiting = "---\nkey: >\n Congrats, pimpt bedrijventerreinen pimpt\n bedrijventerreinen pimpt\n bedrijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testString() { + $dump = Spyc::YAMLDump(array ('key' => array('key_one' => 'Congrats, pimpt bedrijventerreinen!'))); + $awaiting = "---\nkey:\n key_one: Congrats, pimpt bedrijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testStringLong() { + $dump = Spyc::YAMLDump(array ('key' => array('key_one' => 'Congrats, pimpt bedrijventerreinen pimpt bedrijventerreinen pimpt bedrijventerreinen!'))); + $awaiting = "---\nkey:\n key_one: >\n Congrats, pimpt bedrijventerreinen pimpt\n bedrijventerreinen pimpt\n bedrijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testStringDoubleQuote() { + $dump = Spyc::YAMLDump(array ('key' => array('key_one' => array('key_two' => '"Système d\'e-réservation"')))); + $awaiting = "---\nkey:\n key_one:\n key_two: |\n Système d'e-réservation\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testLongStringDoubleQuote() { + $dump = Spyc::YAMLDump(array ('key' => array('key_one' => array('key_two' => '"Système d\'e-réservation bedrijventerreinen pimpt" bedrijventerreinen!')))); + $awaiting = "---\nkey:\n key_one:\n key_two: |\n \"Système d'e-réservation bedrijventerreinen pimpt\" bedrijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testStringStartingWithSpace() { + $dump = Spyc::YAMLDump(array ('key' => array('key_one' => " Congrats, pimpt bedrijventerreinen \n pimpt bedrijventerreinen pimpt bedrijventerreinen!"))); + $awaiting = "---\nkey:\n key_one: |\n Congrats, pimpt bedrijventerreinen\n pimpt bedrijventerreinen pimpt bedrijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testPerCentOne() { + $dump = Spyc::YAMLDump(array ('key' => "%name%, pimpts bedrijventerreinen!")); + $awaiting = "---\nkey: '%name%, pimpts bedrijventerreinen!'\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testPerCentAndSimpleQuote() { + $dump = Spyc::YAMLDump(array ('key' => "%name%, pimpt's bedrijventerreinen!")); + $awaiting = "---\nkey: \"%name%, pimpt's bedrijventerreinen!\"\n"; + $this->assertEquals ($awaiting, $dump); + } + + public function testPerCentAndDoubleQuote() { + $dump = Spyc::YAMLDump(array ('key' => '%name%, pimpt\'s "bed"rijventerreinen!')); + $awaiting = "---\nkey: |\n %name%, pimpt's \"bed\"rijventerreinen!\n"; + $this->assertEquals ($awaiting, $dump); + } + +} diff --git a/lib/vendor/mustangostang/spyc/tests/IndentTest.php b/lib/vendor/mustangostang/spyc/tests/IndentTest.php new file mode 100644 index 0000000000..b7cdcab7d3 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/IndentTest.php @@ -0,0 +1,68 @@ +Y = Spyc::YAMLLoad(__DIR__."/indent_1.yaml"); + } + + public function testIndent_1() { + $this->assertEquals (array ('child_1' => 2, 'child_2' => 0, 'child_3' => 1), $this->Y['root']); + } + + public function testIndent_2() { + $this->assertEquals (array ('child_1' => 1, 'child_2' => 2), $this->Y['root2']); + } + + public function testIndent_3() { + $this->assertEquals (array (array ('resolutions' => array (1024 => 768, 1920 => 1200), 'producer' => 'Nec')), $this->Y['display']); + } + + public function testIndent_4() { + $this->assertEquals (array ( + array ('resolutions' => array (1024 => 768)), + array ('resolutions' => array (1920 => 1200)), + ), $this->Y['displays']); + } + + public function testIndent_5() { + $this->assertEquals (array (array ( + 'row' => 0, + 'col' => 0, + 'headsets_affected' => array ( + array ( + 'ports' => array (0), + 'side' => 'left', + ) + ), + 'switch_function' => array ( + 'ics_ptt' => true + ) + )), $this->Y['nested_hashes_and_seqs']); + } + + public function testIndent_6() { + $this->assertEquals (array ( + 'h' => array ( + array ('a' => 'b', 'a1' => 'b1'), + array ('c' => 'd') + ) + ), $this->Y['easier_nest']); + } + + public function testIndent_space() { + $this->assertEquals ("By four\n spaces", $this->Y['one_space']); + } + + public function testListAndComment() { + $this->assertEquals (array ('one', 'two', 'three'), $this->Y['list_and_comment']); + } + + public function testAnchorAndAlias() { + $this->assertEquals (array ('database' => 'rails_dev', 'adapter' => 'mysql', 'host' => 'localhost'), $this->Y['development']); + $this->assertEquals (array (1 => 'abc'), $this->Y['zzz']); + } + +} diff --git a/lib/vendor/mustangostang/spyc/tests/LoadTest.php b/lib/vendor/mustangostang/spyc/tests/LoadTest.php new file mode 100644 index 0000000000..a25d36fe86 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/LoadTest.php @@ -0,0 +1,17 @@ +assertEquals ($yaml, $yaml_loaded); + } + } +} diff --git a/lib/vendor/mustangostang/spyc/tests/ParseTest.php b/lib/vendor/mustangostang/spyc/tests/ParseTest.php new file mode 100644 index 0000000000..2ce77ca852 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/ParseTest.php @@ -0,0 +1,413 @@ +yaml = spyc_load_file(__DIR__.'/../spyc.yaml'); + } + + public function testMergeHashKeys() { + $Expected = array ( + array ('step' => array('instrument' => 'Lasik 2000', 'pulseEnergy' => 5.4, 'pulseDuration' => 12, 'repetition' => 1000, 'spotSize' => '1mm')), + array ('step' => array('instrument' => 'Lasik 2000', 'pulseEnergy' => 5.4, 'pulseDuration' => 12, 'repetition' => 1000, 'spotSize' => '2mm')), + ); + $Actual = spyc_load_file (__DIR__.'/indent_1.yaml'); + $this->assertEquals ($Expected, $Actual['steps']); + } + + public function testDeathMasks() { + $Expected = array ('sad' => 2, 'magnificent' => 4); + $Actual = spyc_load_file (__DIR__.'/indent_1.yaml'); + $this->assertEquals ($Expected, $Actual['death masks are']); + } + + public function testDevDb() { + $Expected = array ('adapter' => 'mysql', 'host' => 'localhost', 'database' => 'rails_dev'); + $Actual = spyc_load_file (__DIR__.'/indent_1.yaml'); + $this->assertEquals ($Expected, $Actual['development']); + } + + public function testNumericKey() { + $this->assertEquals ("Ooo, a numeric key!", $this->yaml[1040]); + } + + public function testMappingsString() { + $this->assertEquals ("Anyone's name, really.", $this->yaml['String']); + } + + public function testMappingsInt() { + $this->assertSame (13, $this->yaml['Int']); + } + + public function testMappingsHex() { + $this->assertSame (243, $this->yaml['Hex']); + $this->assertSame ('f0xf3', $this->yaml['BadHex']); + } + + public function testMappingsBooleanTrue() { + $this->assertSame (true, $this->yaml['True']); + } + + public function testMappingsBooleanFalse() { + $this->assertSame (false, $this->yaml['False']); + } + + public function testMappingsZero() { + $this->assertSame (0, $this->yaml['Zero']); + } + + public function testMappingsNull() { + $this->assertSame (null, $this->yaml['Null']); + } + + public function testMappingsNotNull() { + $this->assertSame ('null', $this->yaml['NotNull']); + } + + public function testMappingsFloat() { + $this->assertSame (5.34, $this->yaml['Float']); + } + + public function testMappingsNegative() { + $this->assertSame (-90, $this->yaml['Negative']); + } + + public function testMappingsSmallFloat() { + $this->assertSame (0.7, $this->yaml['SmallFloat']); + } + + public function testNewline() { + $this->assertSame ('\n', $this->yaml['NewLine']); + } + + public function testQuotedNewline() { + $this->assertSame ("\n", $this->yaml['QuotedNewLine']); + } + + public function testSeq0() { + $this->assertEquals ("PHP Class", $this->yaml[0]); + } + + public function testSeq1() { + $this->assertEquals ("Basic YAML Loader", $this->yaml[1]); + } + + public function testSeq2() { + $this->assertEquals ("Very Basic YAML Dumper", $this->yaml[2]); + } + + public function testSeq3() { + $this->assertEquals (array("YAML is so easy to learn.", + "Your config files will never be the same."), $this->yaml[3]); + } + + public function testSeqMap() { + $this->assertEquals (array("cpu" => "1.5ghz", "ram" => "1 gig", + "os" => "os x 10.4.1"), $this->yaml[4]); + } + + public function testMappedSequence() { + $this->assertEquals (array("yaml.org", "php.net"), $this->yaml['domains']); + } + + public function testAnotherSequence() { + $this->assertEquals (array("program" => "Adium", "platform" => "OS X", + "type" => "Chat Client"), $this->yaml[5]); + } + + public function testFoldedBlock() { + $this->assertEquals ("There isn't any time for your tricks!\nDo you understand?", $this->yaml['no time']); + } + + public function testLiteralAsMapped() { + $this->assertEquals ("There is nothing but time\nfor your tricks.", $this->yaml['some time']); + } + + public function testCrazy() { + $this->assertEquals (array( array("name" => "spartan", "notes" => + array( "Needs to be backed up", + "Needs to be normalized" ), + "type" => "mysql" )), $this->yaml['databases']); + } + + public function testColons() { + $this->assertEquals ("like", $this->yaml["if: you'd"]); + } + + public function testInline() { + $this->assertEquals (array("One", "Two", "Three", "Four"), $this->yaml[6]); + } + + public function testNestedInline() { + $this->assertEquals (array("One", array("Two", "And", "Three"), "Four", "Five"), $this->yaml[7]); + } + + public function testNestedNestedInline() { + $this->assertEquals (array( "This", array("Is", "Getting", array("Ridiculous", "Guys")), + "Seriously", array("Show", "Mercy")), $this->yaml[8]); + } + + public function testInlineMappings() { + $this->assertEquals (array("name" => "chris", "age" => "young", "brand" => "lucky strike"), $this->yaml[9]); + } + + public function testNestedInlineMappings() { + $this->assertEquals (array("name" => "mark", "age" => "older than chris", + "brand" => array("marlboro", "lucky strike")), $this->yaml[10]); + } + + public function testReferences() { + $this->assertEquals (array('Perl', 'Python', 'PHP', 'Ruby'), $this->yaml['dynamic languages']); + } + + public function testReferences2() { + $this->assertEquals (array('C/C++', 'Java'), $this->yaml['compiled languages']); + } + + public function testReferences3() { + $this->assertEquals (array( + array('Perl', 'Python', 'PHP', 'Ruby'), + array('C/C++', 'Java') + ), $this->yaml['all languages']); + } + + public function testEscapedQuotes() { + $this->assertEquals ("you know, this shouldn't work. but it does.", $this->yaml[11]); + } + + public function testEscapedQuotes_2() { + $this->assertEquals ( "that's my value.", $this->yaml[12]); + } + + public function testEscapedQuotes_3() { + $this->assertEquals ("again, that's my value.", $this->yaml[13]); + } + + public function testQuotes() { + $this->assertEquals ("here's to \"quotes\", boss.", $this->yaml[14]); + } + + public function testQuoteSequence() { + $this->assertEquals ( array( 'name' => "Foo, Bar's", 'age' => 20), $this->yaml[15]); + } + + public function testShortSequence() { + $this->assertEquals (array( 0 => "a", 1 => array (0 => 1, 1 => 2), 2 => "b"), $this->yaml[16]); + } + + public function testQuotedNewlines() { + $this->assertEquals ("First line\nSecond line\nThird line", $this->yaml[17]); + } + + public function testHash_1() { + $this->assertEquals ("Hash", $this->yaml['hash_1']); + } + + public function testHash_2() { + $this->assertEquals ('Hash #and a comment', $this->yaml['hash_2']); + } + + public function testHash_3() { + $this->assertEquals ('Hash (#) can appear in key too', $this->yaml['hash#3']); + } + + public function testEndloop() { + $this->assertEquals ("Does this line in the end indeed make Spyc go to an infinite loop?", $this->yaml['endloop']); + } + + public function testReallyLargeNumber() { + $this->assertEquals ('115792089237316195423570985008687907853269984665640564039457584007913129639936', $this->yaml['a_really_large_number']); + } + + public function testFloatWithZeros() { + $this->assertSame ('1.0', $this->yaml['float_test']); + } + + public function testFloatWithQuotes() { + $this->assertSame ('1.0', $this->yaml['float_test_with_quotes']); + } + + public function testFloatInverse() { + $this->assertEquals ('001', $this->yaml['float_inverse_test']); + } + + public function testIntArray() { + $this->assertEquals (array (1, 2, 3), $this->yaml['int array']); + } + + public function testArrayOnSeveralLines() { + $this->assertEquals (array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), $this->yaml['array on several lines']); + } + + public function testArrayWithCommas() { + $this->assertEquals(array (0, 1), $this->yaml['array with commas']); + } + + public function testmoreLessKey() { + $this->assertEquals ('', $this->yaml['morelesskey']); + } + + public function testArrayOfZero() { + $this->assertSame (array(0), $this->yaml['array_of_zero']); + } + + public function testSophisticatedArrayOfZero() { + $this->assertSame (array('rx' => array ('tx' => array (0))), $this->yaml['sophisticated_array_of_zero']); + } + + public function testSwitches() { + $this->assertEquals (array (array ('row' => 0, 'col' => 0, 'func' => array ('tx' => array(0, 1)))), $this->yaml['switches']); + } + + public function testEmptySequence() { + $this->assertSame (array(), $this->yaml['empty_sequence']); + } + + public function testEmptyHash() { + $this->assertSame (array(), $this->yaml['empty_hash']); + } + + public function testEmptykey() { + $this->assertSame (array('' => array ('key' => 'value')), $this->yaml['empty_key']); + } + + public function testMultilines() { + $this->assertSame (array(array('type' => 'SomeItem', 'values' => array ('blah', 'blah', 'blah', 'blah'), 'ints' => array(2, 54, 12, 2143))), $this->yaml['multiline_items']); + } + + public function testManyNewlines() { + $this->assertSame ('A quick +fox + + +jumped +over + + + + + +a lazy + + + +dog', $this->yaml['many_lines']); + } + + public function testWerte() { + $this->assertSame (array ('1' => 'nummer 1', '0' => 'Stunde 0'), $this->yaml['werte']); + } + + /* public function testNoIndent() { + $this->assertSame (array( + array ('record1'=>'value1'), + array ('record2'=>'value2') + ) + , $this->yaml['noindent_records']); + } */ + + public function testColonsInKeys() { + $this->assertSame (array (1000), $this->yaml['a:1']); + } + + public function testColonsInKeys2() { + $this->assertSame (array (2000), $this->yaml['a:2']); + } + + public function testUnquotedColonsInKeys() { + $this->assertSame (array (3000), $this->yaml['a:3']); + } + + public function testComplicatedKeyWithColon() { + $this->assertSame(array("a:b:''test'" => 'value'), $this->yaml['complex_unquoted_key']); + } + + public function testKeysInMappedValueException() { + $this->setExpectedException('Exception'); + Spyc::YAMLLoad('x: y: z:'); + } + + public function testKeysInValueException() { + $this->setExpectedException('Exception'); + Spyc::YAMLLoad('x: y: z'); + } + + public function testSpecialCharacters() { + $this->assertSame ('[{]]{{]]', $this->yaml['special_characters']); + } + + public function testAngleQuotes() { + $Quotes = Spyc::YAMLLoad(__DIR__.'/quotes.yaml'); + $this->assertEquals (array ('html_tags' => array ('
      ', '

      '), 'html_content' => array ('

      hello world

      ', 'hello
      world'), 'text_content' => array ('hello world')), + $Quotes); + } + + public function testFailingColons() { + $Failing = Spyc::YAMLLoad(__DIR__.'/failing1.yaml'); + $this->assertSame (array ('MyObject' => array ('Prop1' => array ('key1:val1'))), + $Failing); + } + + public function testQuotesWithComments() { + $Expected = 'bar'; + $Actual = spyc_load_file (__DIR__.'/comments.yaml'); + $this->assertEquals ($Expected, $Actual['foo']); + } + + public function testArrayWithComments() { + $Expected = array ('x', 'y', 'z'); + $Actual = spyc_load_file (__DIR__.'/comments.yaml'); + $this->assertEquals ($Expected, $Actual['arr']); + } + + public function testAfterArrayWithKittens() { + $Expected = 'kittens'; + $Actual = spyc_load_file (__DIR__.'/comments.yaml'); + $this->assertEquals ($Expected, $Actual['bar']); + } + + // Plain characters http://www.yaml.org/spec/1.2/spec.html#id2789510 + public function testKai() { + $Expected = array('-example' => 'value'); + $Actual = spyc_load_file (__DIR__.'/indent_1.yaml'); + $this->assertEquals ($Expected, $Actual['kai']); + } + + public function testKaiList() { + $Expected = array ('-item', '-item', '-item'); + $Actual = spyc_load_file (__DIR__.'/indent_1.yaml'); + $this->assertEquals ($Expected, $Actual['kai_list_of_items']); + } + + public function testDifferentQuoteTypes() { + $expected = array ('Something', "", "", "Something else"); + $this->assertSame ($expected, $this->yaml['invoice']); + } + + public function testDifferentQuoteTypes2() { + $expected = array ('Something', "Nothing", "Anything", "Thing"); + $this->assertSame ($expected, $this->yaml['quotes']); + } + + // Separation spaces http://www.yaml.org/spec/1.2/spec.html#id2778394 + public function testMultipleArrays() { + $expected = array(array(array('x'))); + $this->assertSame($expected, Spyc::YAMLLoad("- - - x")); + } + + public function testElementWithEmptyHash() + { + $element = "hash: {}\narray: []"; + $yaml = Spyc::YAMLLoadString($element); + $this->assertEquals($yaml['hash'], []); + $this->assertEquals($yaml['array'], []); + + $yaml = Spyc::YAMLLoadString($element, [ + 'setting_empty_hash_as_object' => true + ]); + $this->assertInstanceOf(stdClass::class, $yaml['hash']); + $this->assertEquals($yaml['array'], []); + } +} diff --git a/lib/vendor/mustangostang/spyc/tests/RoundTripTest.php b/lib/vendor/mustangostang/spyc/tests/RoundTripTest.php new file mode 100644 index 0000000000..3e707dfe87 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/RoundTripTest.php @@ -0,0 +1,76 @@ + $a))); } + + +class RoundTripTest extends PHPUnit_Framework_TestCase { + + protected function setUp() { + } + + public function testNull() { + $this->assertEquals (array ('x' => null), roundTrip (null)); + } + + public function testY() { + $this->assertEquals (array ('x' => 'y'), roundTrip ('y')); + } + + public function testExclam() { + $this->assertEquals (array ('x' => '!yeah'), roundTrip ('!yeah')); + } + + public function test5() { + $this->assertEquals (array ('x' => '5'), roundTrip ('5')); + } + + public function testSpaces() { + $this->assertEquals (array ('x' => 'x '), roundTrip ('x ')); + } + + public function testApostrophes() { + $this->assertEquals (array ('x' => "'biz'"), roundTrip ("'biz'")); + } + + public function testNewLines() { + $this->assertEquals (array ('x' => "\n"), roundTrip ("\n")); + } + + public function testHashes() { + $this->assertEquals (array ('x' => array ("#color" => '#fff')), roundTrip (array ("#color" => '#fff'))); + } + + public function testPreserveString() { + $result1 = roundTrip ('0'); + $result2 = roundTrip ('true'); + $this->assertTrue (is_string ($result1['x'])); + $this->assertTrue (is_string ($result2['x'])); + } + + public function testPreserveBool() { + $result = roundTrip (true); + $this->assertTrue (is_bool ($result['x'])); + } + + public function testPreserveInteger() { + $result = roundTrip (0); + $this->assertTrue (is_int ($result['x'])); + } + + public function testWordWrap() { + $this->assertEquals (array ('x' => "aaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), roundTrip ("aaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")); + } + + public function testABCD() { + $this->assertEquals (array ('a', 'b', 'c', 'd'), Spyc::YAMLLoad(Spyc::YAMLDump(array('a', 'b', 'c', 'd')))); + } + + public function testABCD2() { + $a = array('a', 'b', 'c', 'd'); // Create a simple list + $b = Spyc::YAMLDump($a); // Dump the list as YAML + $c = Spyc::YAMLLoad($b); // Load the dumped YAML + $d = Spyc::YAMLDump($c); // Re-dump the data + $this->assertSame($b, $d); + } + +} diff --git a/lib/vendor/mustangostang/spyc/tests/comments.yaml b/lib/vendor/mustangostang/spyc/tests/comments.yaml new file mode 100644 index 0000000000..c05012f3d1 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/comments.yaml @@ -0,0 +1,3 @@ +foo: 'bar' #Comment +arr: ['x', 'y', 'z'] # Comment here +bar: kittens \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/tests/failing1.yaml b/lib/vendor/mustangostang/spyc/tests/failing1.yaml new file mode 100644 index 0000000000..6906a51c16 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/failing1.yaml @@ -0,0 +1,2 @@ +MyObject: + Prop1: {key1:val1} \ No newline at end of file diff --git a/lib/vendor/mustangostang/spyc/tests/indent_1.yaml b/lib/vendor/mustangostang/spyc/tests/indent_1.yaml new file mode 100644 index 0000000000..62d6ece939 --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/indent_1.yaml @@ -0,0 +1,70 @@ +root: + child_1: 2 + + child_2: 0 + child_3: 1 + +root2: + child_1: 1 +# A comment + child_2: 2 + +displays: + - resolutions: + 1024: 768 + - resolutions: + 1920: 1200 + +display: + - resolutions: + 1024: 768 + 1920: 1200 + producer: "Nec" + +nested_hashes_and_seqs: + - { row: 0, col: 0, headsets_affected: [{ports: [0], side: left}], switch_function: {ics_ptt: true} } + +easier_nest: { h: [{a: b, a1: b1}, {c: d}] } + +one_space: | + By four + spaces + +steps: + - step: &id001 + instrument: Lasik 2000 + pulseEnergy: 5.4 + pulseDuration: 12 + repetition: 1000 + spotSize: 1mm + - step: + <<: *id001 + spotSize: 2mm + +death masks are: + sad: 2 + <<: {magnificent: 4} + +login: &login + adapter: mysql + host: localhost + +development: + database: rails_dev + <<: *login + +"key": "value:" +colon_only: ":" + +list_and_comment: [one, two, three] # comment +kai: + -example: value +kai_list_of_items: + - -item + - '-item' + -item + +&foo bar: + 1: "abc" + +zzz: *foo diff --git a/lib/vendor/mustangostang/spyc/tests/quotes.yaml b/lib/vendor/mustangostang/spyc/tests/quotes.yaml new file mode 100644 index 0000000000..2ceea86aae --- /dev/null +++ b/lib/vendor/mustangostang/spyc/tests/quotes.yaml @@ -0,0 +1,8 @@ +html_tags: + -
      + -

      +html_content: + -

      hello world

      + - hello
      world +text_content: + - hello world \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/.github/FUNDING.yml b/lib/vendor/overtrue/pinyin/.github/FUNDING.yml new file mode 100644 index 0000000000..a3be7fa855 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/.github/FUNDING.yml @@ -0,0 +1,9 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: overtrue +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +custom: # Replace with a single custom sponsorship URL diff --git a/lib/vendor/overtrue/pinyin/LICENSE b/lib/vendor/overtrue/pinyin/LICENSE new file mode 100755 index 0000000000..3975dd5bbf --- /dev/null +++ b/lib/vendor/overtrue/pinyin/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 安正超 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/README.md b/lib/vendor/overtrue/pinyin/README.md new file mode 100755 index 0000000000..61ce9c19c2 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/README.md @@ -0,0 +1,130 @@ +

      Pinyin

      + +

      + +[![Build Status](https://travis-ci.org/overtrue/pinyin.svg?branch=master)](https://travis-ci.org/overtrue/pinyin) +[![Latest Stable Version](https://poser.pugx.org/overtrue/pinyin/v/stable.svg)](https://packagist.org/packages/overtrue/pinyin) [![Total Downloads](https://poser.pugx.org/overtrue/pinyin/downloads.svg)](https://packagist.org/packages/overtrue/pinyin) [![Latest Unstable Version](https://poser.pugx.org/overtrue/pinyin/v/unstable.svg)](https://packagist.org/packages/overtrue/pinyin) [![License](https://poser.pugx.org/overtrue/pinyin/license.svg)](https://packagist.org/packages/overtrue/pinyin) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/overtrue/pinyin/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/overtrue/pinyin/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/overtrue/pinyin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/overtrue/pinyin/?branch=master) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fovertrue%2Fpinyin.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fovertrue%2Fpinyin?ref=badge_shield) + +

      + +:cn: 基于 [CC-CEDICT](http://cc-cedict.org/wiki/) 词典的中文转拼音工具,更准确的支持多音字的汉字转拼音解决方案。 + + +## 安装 + +使用 Composer 安装: + +``` +$ composer require "overtrue/pinyin:~4.0" +``` + +## 使用 + +可选转换方案: + +- 内存型,适用于服务器内存空间较富余,优点:转换快 +- 小内存型(默认),适用于内存比较紧张的环境,优点:占用内存小,转换不如内存型快 +- I/O型,适用于虚拟机,内存限制比较严格环境。优点:非常微小内存消耗。缺点:转换慢,不如内存型转换快,php >= 5.5 + +## 可用选项: + +| 选项 | 描述 | +| ------------- | ---------------------------------------------------| +| `PINYIN_TONE` | UNICODE 式音调:`měi hǎo` | +| `PINYIN_ASCII_TONE` | 带数字式音调: `mei3 hao3` | +| `PINYIN_NO_TONE` | 无音调:`mei hao` | +| `PINYIN_KEEP_NUMBER` | 保留数字 | +| `PINYIN_KEEP_ENGLISH` | 保留英文 | +| `PINYIN_KEEP_PUNCTUATION` | 保留标点 | +| `PINYIN_UMLAUT_V` | 使用 `v` 代替 `yu`, 例如:吕 `lyu` 将会转为 `lv` | + +### 拼音数组 + +```php +use Overtrue\Pinyin\Pinyin; + +// 小内存型 +$pinyin = new Pinyin(); // 默认 +// 内存型 +// $pinyin = new Pinyin('Overtrue\Pinyin\MemoryFileDictLoader'); +// I/O型 +// $pinyin = new Pinyin('Overtrue\Pinyin\GeneratorFileDictLoader'); + +$pinyin->convert('带着希望去旅行,比到达终点更美好'); +// ["dai", "zhe", "xi", "wang", "qu", "lyu", "xing", "bi", "dao", "da", "zhong", "dian", "geng", "mei", "hao"] + +$pinyin->convert('带着希望去旅行,比到达终点更美好', PINYIN_TONE); +// ["dài","zhe","xī","wàng","qù","lǚ","xíng","bǐ","dào","dá","zhōng","diǎn","gèng","měi","hǎo"] + +$pinyin->convert('带着希望去旅行,比到达终点更美好', PINYIN_ASCII_TONE); +//["dai4","zhe","xi1","wang4","qu4","lyu3","xing2","bi3","dao4","da2","zhong1","dian3","geng4","mei3","hao3"] +``` + +- 小内存型: 将字典分片载入内存 +- 内存型: 将所有字典预先载入内存 +- I/O型: 不载入内存,将字典使用文件流打开逐行遍历并运用php5.5生成器(yield)特性分配单行内存 + + +### 生成用于链接的拼音字符串 + +```php +$pinyin->permalink('带着希望去旅行'); // dai-zhe-xi-wang-qu-lyu-xing +$pinyin->permalink('带着希望去旅行', '.'); // dai.zhe.xi.wang.qu.lyu.xing +``` + +### 获取首字符字符串 + +```php +$pinyin->abbr('带着希望去旅行'); // dzxwqlx +$pinyin->abbr('带着希望去旅行', '-'); // d-z-x-w-q-l-x + +$pinyin->abbr('你好2018!', PINYIN_KEEP_NUMBER); // nh2018 +$pinyin->abbr('Happy New Year! 2018!', PINYIN_KEEP_ENGLISH); // HNY2018 +``` + +### 翻译整段文字为拼音 + +将会保留中文字符:`,。 ! ? : “ ” ‘ ’` 并替换为对应的英文符号。 + +```php +$pinyin->sentence('带着希望去旅行,比到达终点更美好!'); +// dai zhe xi wang qu lyu xing, bi dao da zhong dian geng mei hao! + +$pinyin->sentence('带着希望去旅行,比到达终点更美好!', PINYIN_TONE); +// dài zhe xī wàng qù lǚ xíng, bǐ dào dá zhōng diǎn gèng měi hǎo! +``` + +### 翻译姓名 + +姓名的姓的读音有些与普通字不一样,比如 ‘单’ 常见的音为 `dan`,而作为姓的时候读 `shan`。 + +```php +$pinyin->name('单某某'); // ['shan', 'mou', 'mou'] +$pinyin->name('单某某', PINYIN_TONE); // ["shàn","mǒu","mǒu"] +``` + +更多使用请参考 [测试用例](https://github.com/overtrue/pinyin/blob/master/tests/AbstractDictLoaderTestCase.php)。 + +## 在 Laravel 中使用 + +独立的包在这里:[overtrue/laravel-pinyin](https://github.com/overtrue/laravel-pinyin) + +## Contribution +欢迎提意见及完善补充词库 [`overtrue/pinyin-dictionary-maker`](https://github.com/overtrue/pinyin-dictionary-maker/tree/master/patches) :kiss: + +## 参考 + +- [详细参考资料](https://github.com/overtrue/pinyin-resources) + +## PHP 扩展包开发 + +> 想知道如何从零开始构建 PHP 扩展包? +> +> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package) + +# License + +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fovertrue%2Fpinyin.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fovertrue%2Fpinyin?ref=badge_large) diff --git a/lib/vendor/overtrue/pinyin/composer.json b/lib/vendor/overtrue/pinyin/composer.json new file mode 100644 index 0000000000..91786e1642 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/composer.json @@ -0,0 +1,34 @@ +{ + "name": "overtrue/pinyin", + "description": "Chinese to pinyin translator.", + "keywords": [ + "chinese", + "pinyin", + "cn2pinyin" + ], + "homepage": "https://github.com/overtrue/pinyin", + "license": "MIT", + "authors": [ + { + "name": "Carlos", + "homepage": "http://github.com/overtrue" + } + ], + "autoload": { + "psr-4": { + "Overtrue\\Pinyin\\": "src/" + }, + "files": ["src/const.php"] + }, + "autoload-dev": { + "psr-4": { + "Overtrue\\Pinyin\\Test\\": "tests/" + } + }, + "require": { + "php":">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.5" + } +} diff --git a/lib/vendor/overtrue/pinyin/data/surnames b/lib/vendor/overtrue/pinyin/data/surnames new file mode 100644 index 0000000000..9f6072a4ef --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/surnames @@ -0,0 +1,84 @@ + ' mò qí', + '尉迟' => ' yù chí', + '单于' => ' chán yú', + '不' => ' fǒu', + '沈' => ' shěn', + '称' => ' chēng', + '车' => ' chē', + '万' => ' wàn', + '汤' => ' tāng', + '阿' => ' ā', + '丁' => ' dīng', + '强' => ' qiáng', + '仇' => ' qiú', + '叶' => ' yè', + '阚' => ' kàn', + '乐' => ' yuè', + '乜' => ' niè', + '陆' => ' lù', + '殷' => ' yīn', + '牟' => ' móu', + '区' => ' ōu', + '宿' => ' sù', + '俞' => ' yú', + '余' => ' yú', + '齐' => ' qí', + '许' => ' xǔ', + '信' => ' xìn', + '无' => ' wú', + '浣' => ' wǎn', + '艾' => ' ài', + '浅' => ' qiǎn', + '烟' => ' yān', + '蓝' => ' lán', + '於' => ' yú', + '寻' => ' xún', + '殳' => ' shū', + '思' => ' sī', + '鸟' => ' niǎo', + '卜' => ' bǔ', + '单' => ' shàn', + '南' => ' nán', + '柏' => ' bǎi', + '朴' => ' piáo', + '繁' => ' pó', + '曾' => ' zēng', + '瞿' => ' qú', + '缪' => ' miào', + '石' => ' shí', + '冯' => ' féng', + '覃' => ' qín', + '幺' => ' yāo', + '种' => ' chóng', + '折' => ' shè', + '燕' => ' yān', + '纪' => ' jǐ', + '过' => ' guō', + '华' => ' huà', + '冼' => ' xiǎn', + '秘' => ' bì', + '重' => ' chóng', + '解' => ' xiè', + '那' => ' nā', + '和' => ' hé', + '贾' => ' jiǎ', + '塔' => ' tǎ', + '盛' => ' shèng', + '查' => ' zhā', + '盖' => ' gě', + '居' => ' jū', + '哈' => ' hǎ', + '的' => ' dē', + '薄' => ' bó', + '佴' => ' nài', + '六' => ' lù', + '都' => ' dū', + '翟' => ' zhái', + '扎' => ' zā', + '藏' => ' zàng', + '粘' => ' niàn', + '难' => ' nàn', + '若' => ' ruò', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/data/words_0 b/lib/vendor/overtrue/pinyin/data/words_0 new file mode 100644 index 0000000000..f1588f6105 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_0 @@ -0,0 +1,8003 @@ + ' tǎ shí kù ěr gān', + '踉踉跄跄' => ' liàng liàng qiàng qiàng', + '收支差额' => ' shōu zhī chā é', + '只鸡樽酒' => ' zhī jī zūn jiǔ', + '口腹之累' => ' kǒu fù zhī lěi', + '质疑问难' => ' zhì yí wèn nàn', + '收入差距' => ' shōu rù chā jù', + '直言贾祸' => ' zhí yán gǔ huò', + '刻鹄成鹜' => ' kè hú chéng wù', + '克尽厥职' => ' kè jìn jué zhí', + '可逆反应' => ' kě nì fǎn yìng', + '华亭鹤唳' => ' huà tíng hè lì', + '首足异处' => ' shǒu zú yì chǔ', + '还珠合浦' => ' huán zhū hé pǔ', + '认贼作子' => ' rèn zéi zuò zǐ', + '患难夫妻' => ' huàn nàn fū qī', + '课嘴撩牙' => ' kè zuǐ liáo yá', + '认贼为子' => ' rèn zéi wéi zǐ', + '还朴反古' => ' huán pǔ fǎn gǔ', + '长安棋局' => ' cháng ān qí jú', + '置之高阁' => ' zhì zhī gāo gé', + '科学知识' => ' kē xué zhī shi', + '看在眼里' => ' kàn zài yǎn li', + '稚齿婑媠' => ' zhì chǐ wǒ tuǒ', + '指腹为婚' => ' zhǐ fù wéi hūn', + '陟罚臧否' => ' zhì fá zāng pǐ', + '知识分子' => ' zhī shí fèn zǐ', + '知识宝库' => ' zhī shi bǎo kù', + '认贼为父' => ' rèn zéi wéi fù', + '苦苦相逼' => ' kǔ kǔ xiàng bī', + '至当不易' => ' zhì dàng bù yì', + '数米而炊' => ' shǔ mǐ ér chuī', + '破涕为笑' => ' pò tì wéi xiào', + '会计信息' => ' kuài jì xìn xī', + '差之毫厘' => ' chā zhī háo lí', + '差三错四' => ' chā sān cuò sì', + '画龙刻鹄' => ' huà lóng kè hú', + '会计分录' => ' kuài jì fēn lù', + '化害为利' => ' huà hài wéi lì', + '辙乱旗靡' => ' zhé luàn qí mǐ', + '画荻和丸' => ' huà dí huò wán', + '测量记录' => ' cè liáng jì lù', + '看不习惯' => ' kān bù xí guàn', + '只轮无反' => ' zhī lún wú fǎn', + '芝麻开花' => ' zhī ma kāi huā', + '身单力薄' => ' shēn dān lì bó', + '齿牙为祸' => ' chǐ yá wéi huò', + '耻与哙伍' => ' chǐ yú kuài wǔ', + '子宫内膜' => ' zǐ gōng nèi mó', + '温情脉脉' => ' wēn qíng mò mò', + '简丝数米' => ' jiǎn sī shǔ mǐ', + '救苦救难' => ' jiù kǔ jiù nàn', + '三灾八难' => ' sān zāi bā nàn', + '救黥医劓' => ' jiù qíng yī yì', + '尽其所有' => ' jìn qí suǒ yǒu', + '齿牙为猾' => ' chǐ yá wéi huá', + '竭尽心力' => ' jié jìn xīn lì', + '泊松分布' => ' bó sōng fēn bù', + '称体裁衣' => ' chèn tǐ cái yī', + '解衣磅礴' => ' jiě yī páng bó', + '设计要求' => ' shè jì yāo qiú', + '解衣卸甲' => ' jiě yī xiè jiǎ', + '竭智尽力' => ' jié zhì jìn lì', + '尽瘁至死' => ' jìn cuì zhì sǐ', + '九行八业' => ' jiǔ háng bā yè', + '见义必为' => ' jiàn yì bì wéi', + '尽职尽责' => ' jìn zhí jìn zé', + '经史子集' => ' jīng shǐ zǐ jí', + '只轮不反' => ' zhī lún bù fǎn', + '朝云暮雨' => ' zhāo yún mù yǔ', + '逐物不还' => ' zhú wù bù huán', + '独生子女' => ' dú shēng zǐ nǚ', + '深信不疑' => ' shēn xìn bù yí', + '租赁合同' => ' zū lìn hé tong', + '甚而至于' => ' shèn ér zhì yú', + '杀鸡为黍' => ' shā jī wéi shǔ', + '混水摸鱼' => ' hún shuǐ mō yú', + '子孙后代' => ' zǐ sūn hòu dài', + '煞费心机' => ' shà fèi xīn jī', + '混为一谈' => ' hùn wéi yī tán', + '子曰诗云' => ' zǐ yuè shī yún', + '扫眉才子' => ' sǎo méi cái zǐ', + '九垓八埏' => ' jiǔ gāi bā yán', + '自我调节' => ' zì wǒ tiáo jié', + '金鳷擘海' => ' jīn zhī bò hǎi', + '子孙万代' => ' zǐ sūn wàn dài', + '数米量柴' => ' shǔ mǐ ér chái', + '日省月课' => ' rì xǐng yuè kè', + '捐躯赴难' => ' juān qū fù nàn', + '系统设计' => ' xì tǒng shè jì', + '细高挑儿' => ' xì gāo tiǎo ér', + '见素抱朴' => ' xiàn sù bào pǔ', + '阿房宫赋' => ' ē páng gōng fù', + '屙金溺银' => ' ē jīn niào yín', + '遐迩著闻' => ' xiá ěr zhù wén', + '阿党比周' => ' ē dǎng bǐ zhōu', + '朵颐大嚼' => ' duǒ yī dà jiáo', + '误作非为' => ' wù zuò fēi wéi', + '安身为乐' => ' ān shēn wéi lè', + '披发文身' => ' pī fà wén shēn', + '倒峡泻河' => ' dǎo xiá xiè hé', + '捣虚批吭' => ' dǎo xū pī háng', + '攀藤附葛' => ' pān téng fù gě', + '晰毛辨发' => ' xī máo biàn fà', + '多文为富' => ' duō wén wéi fù', + '垂头搨翼' => ' chuí tóu dá yì', + '画荻教子' => ' huà dí jiào zǐ', + '倡而不和' => ' chàng ér bù hè', + '阿谀逢迎' => ' ē yú féng yíng', + '睹微知著' => ' dǔ wēi zhī zhù', + '货而不售' => ' huo er bu shou', + '顿开茅塞' => ' dùn kāi máo sè', + '挨山塞海' => ' āi shān sè hǎi', + '捱三顶五' => ' āi sān dǐng wǔ', + '捱三顶四' => ' āi sān dǐng sì', + '爱人好士' => ' ài rén hào shì', + '旁指曲谕' => ' páng zhǐ qǔ yù', + '无下箸处' => ' wú xià zhù chǔ', + '跑马卖解' => ' pǎo mǎ mài xiè', + '挨冻受饿' => ' ái dòng shòu è', + '捧心西子' => ' pěng xīn xī zǐ', + '污水处理' => ' wū shuǐ chǔ lǐ', + '睹著知微' => ' dǔ zhù zhī wēi', + '开锣喝道' => ' kāi luó hè dào', + '倒载干戈' => ' dào zài gān gē', + '阿平绝倒' => ' ā píng jué dǎo', + '无为之治' => ' wú wéi zhī zhì', + '同心一意' => ' tóng xīn yī yì', + '批风抹月' => ' pī fēng mò yuè', + '鼠疫杆菌' => ' shǔ yì gǎn jūn', + '攫为己有' => ' jué wéi jǐ yǒu', + '当回事儿' => ' dàng huí shì r', + '活跃分子' => ' huó yuè fèn zǐ', + '基本电荷' => ' jī běn diàn hè', + '积德累善' => ' jī dé lěi shàn', + '积谗糜骨' => ' jī chán méi gǔ', + '琴瑟不调' => ' qín sè bù tiáo', + '竹篱茅舍' => ' zhú lí máo shè', + '绝对误差' => ' jué duì wù chā', + '豁然开悟' => ' huò rán kāi wù', + '几不欲生' => ' jī bù yù shēng', + '基本要求' => ' jī běn yāo qiú', + '日新月著' => ' rì xīn yuè zhù', + '玩儿花招' => ' wán r huā zhāo', + '什伍东西' => ' shí wǔ dōng xī', + '铢积寸累' => ' zhū jī cùn lěi', + '用得其所' => ' yòng de qí suǒ', + '什袭而藏' => ' shí xī ér cáng', + '珠还合浦' => ' zhū huán hé pǔ', + '什袭以藏' => ' shí xí yǐ cáng', + '男子篮球' => ' nán zǐ lán qíu', + '豁然确斯' => ' huò rán què sī', + '十魔九难' => ' shí mó jiǔ nàn', + '玩儿得转' => ' wán r dé zhuàn', + '绝子绝孙' => ' jué zǐ jué sūn', + '君子三戒' => ' jūn zǐ sān jiè', + '昼度夜思' => ' zhòu duó yè sī', + '均匀分布' => ' jūn yún fēn bù', + '发奋有为' => ' fā fèn yǒu wéi', + '日进斗金' => ' rì jìn dǒu jīn', + '画地为牢' => ' huà dì wéi láo', + '白马王子' => ' bái mǎ wáng zǐ', + '魂不着体' => ' hún bù zhuó tǐ', + '君子好逑' => ' jūn zǐ hǎo qiú', + '事与心违' => ' shì yù xīn wéi', + '朱盘玉敦' => ' zhū pán yù duì', + '益觉困难' => ' yì jué kùn nan', + '诗云子曰' => ' shī yún zǐ yuè', + '尽心尽力' => ' jìn xīn jìn lì', + '晦盲否塞' => ' huì máng pǐ sè', + '百度知道' => ' bǎi dù zhī dao', + '尽心竭力' => ' jìn xīn jié lì', + '豁然顿悟' => ' huò rán dùn wù', + '急功好利' => ' jí gōng hào lì', + '山雨欲来' => ' shān yǔ yù lái', + '设心处虑' => ' shè xīn chǔ lǜ', + '尽态极妍' => ' jìn tài jí yán', + '过都历块' => ' guò dū lì kuài', + '财殚力尽' => ' cái dān lì jìn', + '鱼书雁帖' => ' yú shū yàn tiě', + '与世沉浮' => ' yú shì chén fú', + '思所逐之' => ' si shuo zhu zi', + '不当人子' => ' bù dāng rén zǐ', + '过甚其辞' => ' guò shèn qí cí', + '诱掖后进' => ' yòu yè hòu jìn', + '燎发摧枯' => ' liǎo fà cuī kū', + '桂子兰孙' => ' guì zǐ lán sūn', + '麇至沓来' => ' qún zhì tà lái', + '舌下含服' => ' shé xià hán fù', + '不差累黍' => ' bù chā lěi shǔ', + '舞台音乐' => ' wǔ tái yīn yuè', + '有人家儿' => ' yǒu rén jiā ér', + '撩云拨雨' => ' liáo yún bō yǔ', + '波属云委' => ' bō zhǔ yún wěi', + '桂折一枝' => ' guì shé yī zhī', + '苦尽甘来' => ' kǔ jìn gān lái', + '不足为怪' => ' bù zú wéi guài', + '河落海干' => ' hé luò hǎi gān', + '圭角不露' => ' guī jiǎo bù lù', + '载驰载驱' => ' zǎi chí zǎi qū', + '没齿无怨' => ' mò chǐ wú yuàn', + '蠡测管窥' => ' lǐ cè guǎn kuī', + '贼臣逆子' => ' zéi chén nì zǐ', + '不足为凭' => ' bù zú wéi píng', + '凿龟数策' => ' záo guī shǔ cè', + '总理衙门' => ' zǒng lǐ yá men', + '臧否人物' => ' zāng pǐ rén wù', + '河清难俟' => ' hé qīng nán sì', + '哺糟啜醨' => ' bǔ zāo chuò lí', + '河南坠子' => ' hé nán zhuì zǐ', + '云朝雨暮' => ' yún zhāo yǔ mù', + '罐头起子' => ' guàn tou qǐ zi', + '合浦珠还' => ' hé pǔ zhū huán', + '置之不问' => ' zhì zhī bù wèn', + '置之度外' => ' zhì zhī dù wài', + '合浦还珠' => ' hé pǔ huán zhū', + '罗锅儿桥' => ' luó guō r qiáo', + '云泥之差' => ' yún ní zhī chā', + '拨云撩雨' => ' bō yún liáo yǔ', + '茅塞顿开' => ' máo sè dùn kāi', + '翘足而待' => ' qiáo zú ér dài', + '朝不保暮' => ' zhāo bù bǎo mù', + '去甚去泰' => ' qù shèn qù tài', + '水尽鹅飞' => ' shuǐ jìn é fēi', + '气势磅礴' => ' qì shì páng bó', + '立地成佛' => ' lì dì chéng fó', + '财务会计' => ' cái wù kuài jì', + '朝发暮至' => ' zhāo fā mù zhì', + '积极反应' => ' jī jí fǎn yìng', + '粪金龟子' => ' fèn jīn guī zǐ', + '积累毒性' => ' jī lěi dú xìng', + '优游卒岁' => ' yōu yóu zú suì', + '材优干济' => ' cái yōu gàn jǐ', + '热闹非凡' => ' rè nao fēi fán', + '重足一迹' => ' chóng zú yī jì', + '朝闻夕死' => ' zhāo wén xī sǐ', + '鹄形菜色' => ' hú xíng cài sè', + '朝三暮二' => ' zhāo sān mù èr', + '劳务合同' => ' láo wù hé tong', + '笃信好学' => ' dǔ xìn hào xué', + '优游自若' => ' yōu yóu zì ruò', + '不见舆薪' => ' bú jiàn yú xīn', + '拨雨撩云' => ' bō yǔ liáo yún', + '好丹非素' => ' hào dān fēi sù', + '拨嘴撩牙' => ' bō zuǐ liáo yá', + '力有未逮' => ' lì yǒu wèi dài', + '曲尽其妙' => ' qū jìn qí miào', + '俟河之清' => ' sì hé zhī qīng', + '离子反应' => ' lí zǐ fǎn yìng', + '舆论哗然' => ' yú lùn huá rán', + '自找麻烦' => ' zì zhǎo má fan', + '自由散漫' => ' zì yóu sǎn màn', + '于今为烈' => ' yú jīn wéi liè', + '鬻鸡为凤' => ' yù jī wéi fèng', + '去太去甚' => ' qù tai qù shèn', + '兴都库什' => ' xīng dū kù shí', + '连鬓胡子' => ' lián bìn hú zǐ', + '与时消息' => ' yǔ shí xiāo xi', + '与此同时' => ' yú cǐ tóng shí', + '兴利除弊' => ' xīng lì chú bì', + '于家为国' => ' yú jiā wéi guó', + '兴安运河' => ' xīng ān yùn hé', + '绿林好汉' => ' lù lín hǎo hàn', + '赫赫之功' => ' hè hè zhì gōng', + '阿世盗名' => ' ē shì dào míng', + '奇偶校验' => ' jī ǒu jiào yàn', + '鞠为茂草' => ' jū wéi mào cǎo', + '积岁累月' => ' jī suì lěi yuè', + '技术要求' => ' jì shù yāo qiú', + '肌肉萎缩' => ' jī ròu wěi suō', + '物尽其用' => ' wù jìn qí yòng', + '肉薄骨并' => ' ròu bó gǔ bìng', + '日月入怀' => ' rì yuè rù huái', + '主要部分' => ' zhǔ yào bù fen', + '狼子野心' => ' láng zǐ yě xīn', + '聚米为山' => ' jù mǐ wéi shān', + '爆冷门儿' => ' bào lěng mén r', + '漠然置之' => ' mò rán zhì zhī', + '无的放矢' => ' wú dì fàng shǐ', + '橘化为枳' => ' jú huà wéi zhǐ', + '擢发莫数' => ' zhuó fà mò shǔ', + '三邻四舍' => ' sān lín sì shè', + '剪发杜门' => ' jiǎn fà dù mén', + '三大差别' => ' sān dà chā bié', + '燕太子丹' => ' yān tài zǐ dān', + '如登春台' => ' rú dé chūn tái', + '灰不溜秋' => ' huī bu līu qīu', + '淡泊寡味' => ' dàn bó guǎ wèi', + '金尽裘敝' => ' jīn jìn qiú bì', + '浮云朝露' => ' fú yún zhāo lù', + '罪恶昭著' => ' zuì è zhāo zhù', + '蛇心佛口' => ' shé xīn fó kǒu', + '钻心刺骨' => ' zuàn xīn cì gǔ', + '折腰五斗' => ' shé yāo wǔ dòu', + '淋漓尽致' => ' lín lí jìn zhì', + '淡泊名利' => ' dàn bó míng lì', + '独立钻石' => ' dú lì zuàn shí', + '拽布披麻' => ' zhuài bù pī má', + '肩摩毂接' => ' jiān mó gū jiē', + '汉藏语系' => ' hàn zàng yǔ xì', + '无能为力' => ' wú néng wéi lì', + '骥子龙文' => ' jì zǐ lóng wén', + '积铢累寸' => ' jī zhū lěi cùn', + '煞费苦心' => ' shà fèi kǔ xīn', + '入理切情' => ' rù lǐ qiē qíng', + '拽耙扶犁' => ' zhuāi pá fú lí', + '居不重席' => ' jū bù chóng xí', + '家无担石' => ' jiā wú dàn shí', + '脊索动物' => ' jǐ suǒ dòng wù', + '处理方法' => ' chǔ lǐ fāng fǎ', + '考波什堡' => ' kǎo bō shí bǎo', + '不肖子孙' => ' bù xiào zǐ sūn', + '群居穴处' => ' qún jū xué chǔ', + '好问决疑' => ' hào wèn jué yí', + '理论知识' => ' lǐ lùn zhī shi', + '解甲倒戈' => ' jiě jiǎ dǎo gē', + '好事之徒' => ' hào shì zhī tú', + '玉卮无当' => ' yù zhī wú dàng', + '鱼游燋釜' => ' yú yóu zhuó fǔ', + '呵壁问天' => ' hē bì wèn tiān', + '听而不闻' => ' tīng ér bú wén', + '肉毒杆菌' => ' ròu dú gǎn jūn', + '胡作非为' => ' hú zuò fēi wéi', + '脉轮理论' => ' mài lún lǐ lùn', + '处理系统' => ' chǔ lǐ xì tǒng', + '不露圭角' => ' bù lù guī jiǎo', + '好骑者堕' => ' hào qí zhě duò', + '聚酯树脂' => ' jù zhǐ shù zhī', + '老鼠尾巴' => ' lǎo shǔ wěi ba', + '老少无欺' => ' lǎo shào wú qī', + '炭疽杆菌' => ' tàn jū gǎn jūn', + '架肩击毂' => ' jià jiān jī gū', + '无业闲散' => ' wú yè xián sǎn', + '举措不当' => ' jǔ cuò bù dàng', + '三差五错' => ' sān chā wǔ cuò', + '三不拗六' => ' sān bù niù liù', + '为所欲为' => ' wéi suǒ yù wéi', + '为时不晚' => ' wéi shí bù wǎn', + '为时已晚' => ' wéi shí yǐ wǎn', + '假模假式' => ' jiǎ mú jiǎ shì', + '塞翁得马' => ' sài wēng dé mǎ', + '河伯为患' => ' hé bó wéi huàn', + '鞠躬君子' => ' jū gōng jūn zǐ', + '无所作为' => ' wú suǒ zuò wéi', + '聚合反应' => ' jù hé fǎn yìng', + '假日经济' => ' jià rì jīng jì', + '朝夷暮跖' => ' zhāo yí mù zhí', + '口似悬河' => ' kǒu sì xuán hé', + '鹤发童颜' => ' hè fà tóng yán', + '离鸾别鹄' => ' lí luán bié hú', + '爱生恶死' => ' ài shēng wù sǐ', + '拔本塞源' => ' bá běn sè yuán', + '窥间伺隙' => ' kuī jiàn sì xì', + '薄技在身' => ' bó jì zài shēn', + '冰解的破' => ' bīng jiě dì pò', + '狗颠屁股' => ' gǒu diān pì gu', + '姑射神人' => ' gū yè shén rén', + '因树为屋' => ' yīn shù wéi wū', + '伯乐相马' => ' bó lè xiàng mǎ', + '广譬曲谕' => ' guǎng pì qǔ yù', + '萎靡不振' => ' wěi mǐ bù zhèn', + '临深履薄' => ' lín shēn lǚ bó', + '绿林豪杰' => ' lù lín háo jié', + '观者如堵' => ' guān zhě rú dǔ', + '肆意妄为' => ' sì yì wàng wéi', + '波骇云属' => ' bō hài yún zhǔ', + '裘弊金尽' => ' qiú bì jīn jìn', + '应答如流' => ' yìng dá rú liú', + '鼓乐齐鸣' => ' gǔ yuè qí míng', + '引以为戒' => ' yǐn yǐ wéi jiè', + '蒙古大夫' => ' měng gǔ dài fu', + '狗屁倒灶' => ' gǒu pì dǎo zào', + '一之已甚' => ' yī zhī yǐ shèn', + '引以为耻' => ' yǐn yǐ wéi chǐ', + '虚心好学' => ' xū xīn hào xué', + '故态复还' => ' gù tài fù huán', + '苏打饼干' => ' sū dá bǐng gān', + '故事片儿' => ' gù shì piān er', + '七十二行' => ' qī shí èr háng', + '孤鸾寡鹄' => ' gū luán guǎ hú', + '因祸为福' => ' yīn huò wéi fú', + '孤鸿寡鹄' => ' gū hóng guǎ hú', + '处理能力' => ' chǔ lǐ néng lì', + '古调不弹' => ' gǔ diào bù tán', + '以珠弹雀' => ' yǐ zhū tán què', + '夙兴夜处' => ' sù xīng yè chǔ', + '孤臣孽子' => ' gū chén niè zǐ', + '露红烟绿' => ' lù hóng yān lǜ', + '随风而靡' => ' suí fēng ér mǐ', + '啜食吐哺' => ' chuò shí tǔ bǔ', + '融为一体' => ' róng wéi yī tǐ', + '衣租食税' => ' yì zū shí shuì', + '蛮横无理' => ' mán hèng wú lǐ', + '引以为豪' => ' yǐn yǐ wéi háo', + '流行歌曲' => ' liú xíng gē qǔ', + '背曲腰弯' => ' bèi qǔ yāo wān', + '遗老遗少' => ' yí lǎo yí shào', + '门殚户尽' => ' mén dān hù jìn', + '一目数行' => ' yī mù shù háng', + '岗头泽底' => ' gāng tóu zé dǐ', + '衣马轻肥' => ' yì mǎ qīng féi', + '弥缝其阙' => ' mí féng qí què', + '蜜里调油' => ' mì lǐ tiáo yóu', + '以利累形' => ' yǐ lì lěi xíng', + '调三窝四' => ' tiáo sān wō sì', + '一日三省' => ' yī rì sān xǐng', + '奔走呼号' => ' bēn zǒu hū háo', + '绰有余裕' => ' chuò yǒu yú yù', + '亲力亲为' => ' qīn lì qīn wéi', + '视为畏途' => ' shì wéi wèi tú', + '躬自菲薄' => ' gōng zì fěi bó', + '此唱彼和' => ' cǐ chàng bǐ hè', + '蹙蹙靡骋' => ' cù cù mǐ chěng', + '亿兆一心' => ' yì zhào yī xīn', + '掠美市恩' => ' lüě měi shì ēn', + '没头没尾' => ' méi tóu mò wěi', + '依头缕当' => ' yī tóu lǚ dàng', + '吹弹得破' => ' chuī tán dé pò', + '亲密无间' => ' qīn mì wú jiàn', + '薄利多销' => ' bó lì duō xiāo', + '吹弹歌舞' => ' chuī tán gē wǔ', + '屏气慑息' => ' bǐng qì shè xī', + '寡鹄孤鸾' => ' guǎ hú gū luán', + '挂席为门' => ' guà xí wéi mén', + '调和分析' => ' tiáo hé fēn xī', + '情凄意切' => ' qíng qī yì qiē', + '绿林豪士' => ' lù lín háo shì', + '一头儿沉' => ' yī tou er chén', + '弹丝品竹' => ' tán sī pǐn zhú', + '寸积铢累' => ' cùn jī zhū lěi', + '观衅伺隙' => ' guān xìn sì xì', + '贪惏无餍' => ' tān lín wú yàn', + '避军三舍' => ' bì jūn sān shè', + '以是为恨' => ' yǐ shì wéi hèn', + '各自为战' => ' gè zì wéi zhàn', + '碧波万顷' => ' bì bō wàn qǐng', + '毛发倒竖' => ' máo fā dǎo shù', + '以苦为荣' => ' yǐ kǔ wéi róng', + '谋为不轨' => ' móu wéi bù guǐ', + '落后分子' => ' luò hòu fēn zǐ', + '起重葫芦' => ' qǐ chóng hú lu', + '大难临头' => ' dà nàn lín tóu', + '费尽心思' => ' fèi jìn xīn si', + '大处着墨' => ' dà chù zhuó mò', + '质子轰击' => ' zhì zǐ hōng jī', + '大行大市' => ' dà háng dà shì', + '赤子之心' => ' chì zǐ zhī xīn', + '赤字累累' => ' chì zì lěi lěi', + '绵力薄材' => ' mián lì bó cái', + '起飞弹射' => ' qǐ fēi tán shè', + '以古为镜' => ' yǐ gǔ wéi jìng', + '一干人犯' => ' yī gān rén fàn', + '大辂椎轮' => ' dà lù zhuī lún', + '费尽心机' => ' fèi jìn xīn jī', + '一蹶不兴' => ' yī juě bù xīng', + '叨在知己' => ' tāo zài zhī jǐ', + '逃灾避难' => ' táo zāi bì nàn', + '哑子做梦' => ' yǎ zǐ zuò mèng', + '哑子寻梦' => ' yǎ zǐ xún mèng', + '以古为鉴' => ' yǐ gǔ wéi jiàn', + '霓裳羽衣' => ' ní cháng yǔ yī', + '芽孢杆菌' => ' yá bāo gǎn jūn', + '父严子孝' => ' fù yán zǐ xiào', + '福为祸始' => ' fú wéi huò shǐ', + '浮收勒索' => ' fú shōu lè suǒ', + '浮收勒折' => ' fú shōu lè shé', + '浮皮潦草' => ' fú pí liáo cǎo', + '名流巨子' => ' míng liú jù zǐ', + '仰事俯畜' => ' yǎng shì fǔ xù', + '迄今为止' => ' qì jīn wéi zhǐ', + '伏而咶天' => ' fú ér shì tiān', + '近似等级' => ' jìn sì děng jí', + '豪气干云' => ' háo qì gān yún', + '身体部分' => ' shēn tǐ bù fèn', + '切理厌心' => ' qiē lǐ yàn xīn', + '衣锦夜行' => ' yì jǐn yè xíng', + '诸子十家' => ' zhū zǐ shí jiā', + '诸子百家' => ' zhū zǐ bǎi jiā', + '一还一报' => ' yī huán yī bào', + '绵薄之力' => ' mián bó zhī lì', + '撮科打哄' => ' cuō kē dǎ hòng', + '哑子托梦' => ' yǎ zǐ tuō mèng', + '没食子酸' => ' méi sì zǐ suān', + '岩栖穴处' => ' yán qī xué chǔ', + '凤靡鸾吪' => ' fèng mǐ luán é', + '舍身饲虎' => ' shè shēn sì hǔ', + '莫此为甚' => ' mò cǐ wéi shèn', + '抹粉施脂' => ' mò fěn shī zhī', + '提高认识' => ' tí gāo rèn shi', + '燕市悲歌' => ' yān shì bēi gē', + '燕雀处屋' => ' yàn què chǔ wū', + '没世不忘' => ' mò shì bù wàng', + '道德认识' => ' dào dé rèn shi', + '言气卑弱' => ' yan qi bei ruo', + '佛头加秽' => ' fó tóu jiā huì', + '摸门不着' => ' mō mén bù zháo', + '脉脉含情' => ' mò mò hán qíng', + '风禾尽起' => ' fēng hé jìn qǐ', + '岩居穴处' => ' yán jū xué chǔ', + '燕金募秀' => ' yān jīn mù xiù', + '燕驾越毂' => ' yān jià yuè gū', + '风号雨泣' => ' fēng háo yǔ qì', + '燕歌赵舞' => ' yān gē zhào wǔ', + '眼饧耳热' => ' yǎn xíng ěr rè', + '特殊要求' => ' tè shū yāo qiú', + '天覆地载' => ' tiān fù dì zǎi', + '匪伊朝夕' => ' fěi yí zhāo xī', + '分液漏斗' => ' fēn yè lòu dǒu', + '炫玉贾石' => ' xuàn yù gǔ shí', + '分毫不差' => ' fēn háo bù chā', + '玄酒瓠脯' => ' xuán jiǔ hù fǔ', + '恬不为意' => ' tián bù wéi yì', + '摸头不着' => ' mō tóu bù zháo', + '奋发有为' => ' fèn fā yǒu wéi', + '虚应故事' => ' xū yìng gù shì', + '莫为已甚' => ' mò wéi yǐ shèn', + '佛心蛇口' => ' fó xīn shé kǒu', + '飞檐走脊' => ' fēi yán zǒu jǐ', + '莫知所为' => ' mò zhī suǒ wéi', + '重足而立' => ' chóng zú ér lì', + '墨汁未干' => ' mò zhī wèi gān', + '重眼皮儿' => ' chóng yǎn pí r', + '退避三舍' => ' tuì bì sān shè', + '弹丸黑子' => ' dàn wán hēi zǐ', + '奉公不阿' => ' fèng gōng bù ē', + '沓来麕至' => ' tà lái yǒu zhì', + '衣裳钩儿' => ' yī shang gōu r', + '都头异姓' => ' dū tóu yì xìng', + '瓦查尿溺' => ' wǎ chá niào nì', + '高丽棒子' => ' gāo lí bàng zi', + '头半天儿' => ' tóu bàn tiān r', + '为裘为箕' => ' wéi qiú wéi jī', + '唯邻是卜' => ' wéi lín shì bǔ', + '托物寓兴' => ' tuō wù yù xīng', + '为虺弗摧' => ' wéi huǐ fú cuī', + '高高手儿' => ' gāo gāo shǒu r', + '高能粒子' => ' gāo néng lì zǐ', + '为鬼为蜮' => ' wéi guǐ wéi yù', + '非都会郡' => ' fēi dū huì jùn', + '外合里应' => ' wài hé lǐ yìng', + '帏薄不修' => ' wéi báo bù xiū', + '预备知识' => ' yù bèi zhī shi', + '为期不远' => ' wéi qī bù yuǎn', + '关门弟子' => ' guān mén dì zǐ', + '调剂余缺' => ' tiáo jì yú quē', + '钻木取火' => ' zuàn mù qǔ huǒ', + '犯而不校' => ' fàn ér bù jiào', + '鞠躬尽力' => ' jū gōng jìn lì', + '非异人任' => ' fēi yì rén rèn', + '挠直为曲' => ' náo zhí wéi qū', + '起偃为竖' => ' qǐ yǎn wéi shù', + '气吞牛斗' => ' qì tūn niú dǒu', + '万夫不当' => ' wàn fū bù dāng', + '颠仆流离' => ' diān pú liú lí', + '七行俱下' => ' qī háng jù xià', + '奇技淫巧' => ' qí jì yín qiǎo', + '饿莩载道' => ' è piǎo zài dào', + '饿莩遍野' => ' è piǎo biàn yě', + '讫情尽意' => ' qì qíng jìn yì', + '鼎折餗覆' => ' dǐng shé sù fù', + '惟日为岁' => ' wéi rì wéi suì', + '铺胸纳地' => ' pū xiōng nà dì', + '电子杂志' => ' diàn zǐ zá zhì', + '鼎折覆餗' => ' dǐng shé fù sù', + '涤故更新' => ' dí gù gēng xīn', + '为蛇画足' => ' wéi shé huà zú', + '味如嚼蜡' => ' wèi rú jiáo là', + '铺锦列绣' => ' pū jǐn liè xiù', + '蒲柳之质' => ' pú liǔ zhī zhì', + '脑脊髓炎' => ' nǎo jǐ suǐ yán', + '叨陪末座' => ' tāo péi mò zuò', + '欺行霸市' => ' qī háng bà shì', + '铺盖卷儿' => ' pū gài juǎn ér', + '拿糖作醋' => ' ná táng zuò cù', + '千载一日' => ' qiān zǎi yī rì', + '南贩北贾' => ' nán fàn běi gǔ', + '反应速度' => ' fǎn yìng sù dù', + '百辞莫辩' => ' bǎi cí mò biàn', + '银行业务' => ' yín háng yè wù', + '铺天盖地' => ' pū tiān gài dì', + '道尽途殚' => ' dào jìn tú dān', + '白发丹心' => ' bái fà dān xīn', + '犯罪分子' => ' fàn zuì fēn zǐ', + '蹈厉之志' => ' dǎo lì zhī zhì', + '兴家立业' => ' xīng jiā lì yè', + '行号卧泣' => ' xíng háo wò qì', + '反劳为逸' => ' fǎn láo wéi yì', + '铁板茄子' => ' tiě bǎn qié zi', + '铁杆粉丝' => ' tiě gǎn fěn sī', + '番窠倒臼' => ' fān kē dǎo jiù', + '难割难舍' => ' nán gē nán shè', + '暮雨朝云' => ' mù yǔ zhāo yún', + '白发偕老' => ' bái fà xié lǎo', + '八难三灾' => ' bā nàn sān zāi', + '二竖为虐' => ' èr shù wéi nüè', + '逆臣贼子' => ' nì chén zéi zǐ', + '孝子慈孙' => ' xiào zǐ cí sūn', + '小眼薄皮' => ' xiǎo yǎn bó pí', + '难进易退' => ' nan jin yi tui', + '前徒倒戈' => ' qián tú dǎo gē', + '八斗之才' => ' bā dǒu zhī cái', + '小姑独处' => ' xiǎo gū dú chǔ', + '法定假日' => ' fǎ dìng jià rì', + '儿女亲家' => ' ér nǚ qìng jiā', + '白发朱颜' => ' bái fà zhū yán', + '调三斡四' => ' tiáo sān wò sì', + '逆子贼臣' => ' nì zǐ zéi chén', + '孽子孤臣' => ' niè zǐ gū chén', + '繁花似锦' => ' fán huā sì jǐn', + '千载奇遇' => ' qiān zǎi qí yù', + '暮虢朝虞' => ' mù guó zhāo yú', + '千载一遇' => ' qiān zǎi yī yù', + '沐猴衣冠' => ' mù hóu yī guàn', + '万夫莫当' => ' wàn fū mò dāng', + '风靡一时' => ' fēng mǐ yī shí', + '攒三集五' => ' cuán sān jí wǔ', + '鸠摩罗什' => ' jīu mó luó shí', + '麦盖提县' => ' mài gě tí xiàn', + '等离子态' => ' děng lí zǐ tài', + '电子学系' => ' diàn zǐ xué xì', + '丽池卡登' => ' lí chí kǎ dēng', + '咸津津儿' => ' xián jīn jīn r', + '屠门大嚼' => ' tú mén dà jiáo', + '头会箕赋' => ' tóu kuài jī fù', + '撇呆打堕' => ' piě dāi dǎ duò', + '东猎西渔' => ' dōng liè xī yú', + '前仆后踣' => ' qián pú hòu bó', + '电子货币' => ' diàn zǐ huò bì', + '电子游戏' => ' diàn zǐ yóu xì', + '平铺直叙' => ' píng pū zhí xù', + '东扶西倒' => ' dōng fú xī dǎo', + '吞言咽理' => ' tūn yán yān lǐ', + '破觚为圜' => ' pò gū wéi yuán', + '破坏荷载' => ' pò huài hè zài', + '破家为国' => ' pò jiā wéi guó', + '文子文孙' => ' wén zǐ wén sūn', + '片词只句' => ' piàn cí zhī jù', + '破矩为圆' => ' pò jǔ wéi yuán', + '履薄临深' => ' lǚ bó lín shēn', + '视为知己' => ' shì wéi zhī jǐ', + '攒三聚五' => ' cuán sān jù wǔ', + '以言为讳' => ' yǐ yán wéi huì', + '贪财好色' => ' tān cái hào sè', + '里应外合' => ' lǐ yìng wài hé', + '西塞山区' => ' xī sài shān qū', + '一无长物' => ' yī wú cháng wù', + '西子捧心' => ' xī zǐ pěng xīn', + '以微知著' => ' yǐ wēi zhī zhù', + '涡轮增压' => ' wō lún zēng yà', + '变贪厉薄' => ' biǎn tān lì bó', + '以退为进' => ' yǐ tuì wéi jìn', + '琴瑟调和' => ' qín sè tiáo hé', + '伺瑕导蠙' => ' sì xiá dǎo pín', + '倒持干戈' => ' dǎo chí gān gē', + '倒持戈矛' => ' dǎo chí gē máo', + '倒置干戈' => ' dào zhì gān gē', + '斗南一人' => ' dǒu nán yī rén', + '品竹弹丝' => ' pǐn zhú tán sī', + '难以应付' => ' nán yǐ yìng fù', + '风雨欲来' => ' fēng yǔ yù lái', + '七颠八倒' => ' qī diān bā dǎo', + '五尺童子' => ' wǔ chǐ tóng zǐ', + '默诵佛号' => ' mò sòng fó hào', + '被山带河' => ' pī shān dài hé', + '屋舍俨然' => ' wū shè yǎn rán', + '破崖绝角' => ' pò yá jué jiǎo', + '霍林郭勒' => ' huò lín guō lè', + '惊叹不已' => ' jīng tàn bù yǐ', + '电子信息' => ' diàn zǐ xìn xī', + '递兴递废' => ' dì xīng dì fèi', + '隐身草儿' => ' yǐn shēn cǎo r', + '莞尔而笑' => ' wǎn ěr ér xiào', + '莞尔一笑' => ' wǎn ěr yī xiào', + '颠覆分子' => ' diān fù fèn zǐ', + '忘恩失义' => ' wàng ēn shī yì', + '王八羔子' => ' wáng bā gāo zǐ', + '栖风宿雨' => ' qī fēng xiǔ yǔ', + '起根由头' => ' qǐ gēn yóu tou', + '七病八倒' => ' qī bìng bā dǎo', + '只鸡斗酒' => ' zhī jī dǒu jiǔ', + '无颠无倒' => ' wú diān wú dǎo', + '杂和面儿' => ' zá huo miàn er', + '杜门面壁' => ' dù mén mian bì', + '阿拉善盟' => ' a lā shàn méng', + '阿松森岛' => ' a sōng sēn dǎo', + '阿森松岛' => ' a sēn sōng dǎo', + '读书得间' => ' dú shū dé jiàn', + '无能为役' => ' wú néng wéi yì', + '阿空加瓜' => ' a kōng jiā guā', + '笃实好学' => ' dǔ shí hào xué', + '杜门自守' => ' dù mén zì shòu', + '批吭捣虚' => ' pī háng dǎo xū', + '无动为大' => ' wú dòng wéi dà', + '被褐怀珠' => ' pī hè huái zhū', + '批砉导窾' => ' pī huā dǎo táo', + '头出头没' => ' tóu chū tóu mò', + '否极阳回' => ' pǐ jí yáng huí', + '五方杂处' => ' wǔ fāng zá chǔ', + '童颜鹤发' => ' tóng yán hè fà', + '斗挹箕扬' => ' dǒu yì jī yáng', + '五斗折腰' => ' wǔ dǒu zhé yāo', + '乐尽悲来' => ' lè jìn bēi lái', + '朝不谋夕' => ' zhāo bù móu xī', + '率马以骥' => ' shuài mǎ yǐ jì', + '蜂扇蚁聚' => ' fēng shān yǐ jù', + '膏唇岐舌' => ' gào chún qí shé', + '孟什维克' => ' mèng shí wéi kè', + '啦啦队长' => ' lā lā duì zhǎng', + '名我固当' => ' ming wo gu dang', + '佛头着粪' => ' fó tóu zhuó fèn', + '摸不着边' => ' mō bù zhuó biān', + '奉为楷模' => ' fèng wéi kǎi mó', + '枫桥夜泊' => ' fēng qiáo yè bó', + '工作态度' => ' gōng zuò tài du', + '风流才子' => ' fēng liú cái zǐ', + '鸣锣喝道' => ' míng luó hè dào', + '丰富知识' => ' fēng fù zhī shi', + '蜂攒蚁聚' => ' fēng cuán yǐ jù', + '蜂攒蚁集' => ' fēng cuán yǐ jí', + '凤雏麟子' => ' fèng chú lín zǐ', + '风驰草靡' => ' fēng chí cǎo mǐ', + '没世难忘' => ' mò shì nán wàng', + '分风劈流' => ' fēn fēng pǐ liú', + '公共服务' => ' gōng gòng fú wù', + '帝王切开' => ' dì wáng qiē kāi', + '钩章棘句' => ' gōu zhāng jí jù', + '貌似强大' => ' mào sì qiáng dà', + '功薄蝉翼' => ' gōng bó chán yì', + '尖酸刻薄' => ' jiān suān kè bó', + '顾曲周郎' => ' gù qǔ zhōu láng', + '鼓角齐鸣' => ' gǔ jiǎo qí míng', + '故技重演' => ' gù jì chóng yǎn', + '古调单弹' => ' gǔ diào dān tán', + '狗追耗子' => ' gǒu zhuī hào zǐ', + '狗续侯冠' => ' gǒu xù hòu guàn', + '落草为寇' => ' luò cǎo wéi kòu', + '功夫片儿' => ' gōng fū piān er', + '小里小气' => ' xiǎo li xiǎo qì', + '工作任务' => ' gōng zuò rèn wu', + '公正不阿' => ' gōng zhèng bù ē', + '工业会计' => ' gōng yè kuài jì', + '供认不讳' => ' gòng rèn bù huì', + '哗啦一声' => ' huā lā yī shēng', + '乱作胡为' => ' luàn zuò hú wéi', + '唾面自干' => ' tuò miàn zì gān', + '分外妖娆' => ' fèn wài yāo ráo', + '膏粱子弟' => ' gāo liáng zǐ dì', + '以眼还眼' => ' yǐ yǎn huán yǎn', + '诛尽杀绝' => ' zhū jìn shā jué', + '详尽无遗' => ' xiáng jìn wú yí', + '词项逻辑' => ' cí xiàng luó ji', + '一日之长' => ' yī rì zhī cháng', + '任人唯亲' => ' rèn rén wéi qīn', + '一时千载' => ' yī shí qiān zǎi', + '设身处地' => ' shè shēn chǔ dì', + '仰屋著书' => ' yǎng wū zhù shū', + '以疏间亲' => ' yǐ shū jiàn qīn', + '黄发儿齿' => ' huáng fà ér chǐ', + '以人为镜' => ' yǐ rén wéi jìng', + '有失厚道' => ' yǒu shī hòu dao', + '有求必应' => ' yǒu qiú bì yìng', + '觅食行为' => ' mì shí xíng wéi', + '一网尽扫' => ' yī wǎng jìn sǎo', + '有缘无分' => ' yǒu yuán wú fèn', + '令人发指' => ' lìng rén fà zhǐ', + '要买人心' => ' yāo mǎi rén xīn', + '扯纤拉烟' => ' chě qiàn lā yān', + '称家有无' => ' chèn jiā yǒu wú', + '缝缝补补' => ' féng féng bǔ bǔ', + '父债子还' => ' fù zhài zǐ huán', + '蒙蒙细雨' => ' mēng mēng xì yǔ', + '福为祸先' => ' fú wéi huò xiān', + '靡靡之声' => ' mǐ mǐ zhī shēng', + '敢作敢为' => ' gǎn zuò gǎn wéi', + '敢为敢做' => ' gǎn wéi gǎn zuò', + '棉花套子' => ' mián huā tào zǐ', + '干卿底事' => ' gān qīng dǐ shì', + '干名采誉' => ' gān míng cǎi yù', + '干将莫邪' => ' gān jiàng mò yé', + '干戈扰攘' => ' gān gē rǎo rǎng', + '面谩腹诽' => ' miàn màn fù fěi', + '甘分随时' => ' gān fèn suí shí', + '左邻右舍' => ' zuǒ lín yòu shè', + '甘处下流' => ' gān chǔ xià liú', + '喇叭水仙' => ' lā bā shuǐ xiān', + '勉为其难' => ' miǎn wéi qí nán', + '善自为谋' => ' shàn zì wéi móu', + '邈处欿视' => ' miǎo chǔ jī shì', + '埋三怨四' => ' mán sān yuàn sì', + '锚固长度' => ' máo gù cháng dù', + '意兴索然' => ' yì xīng suǒ rán', + '品竹调丝' => ' pǐn zhú tiáo sī', + '几可乱真' => ' jī kě luàn zhēn', + '难以为情' => ' nán yǐ wéi qíng', + '内省不疚' => ' nèi xǐng bù jiù', + '难更仆数' => ' nán gēng pú shǔ', + '分兵把口' => ' fèn bīng bǎ kǒu', + '咬文嚼字' => ' yǎo wén jiáo zì', + '培训要求' => ' péi xùn yāo qiú', + '东邻西舍' => ' dōng lín xī shè', + '平均误差' => ' píng jūn wù chā', + '反间之计' => ' fǎn jiàn zhī jì', + '弹痕累累' => ' dàn hén léi léi', + '凭虚公子' => ' píng xū gōng zǐ', + '弹道导弹' => ' dàn dào dǎo dàn', + '刁钻刻薄' => ' diāo zuān kè bó', + '铺眉蒙眼' => ' pū méi méng yǎn', + '雕蚶镂蛤' => ' diāo hān lòu gé', + '东飘西泊' => ' dōng piāo xī bó', + '仆仆风尘' => ' pú pú fēng chén', + '难乎为情' => ' nán hū wéi qíng', + '反目为仇' => ' fǎn mù wéi chóu', + '电子音乐' => ' diàn zǐ yīn yuè', + '泥名失实' => ' nì míng shī shí', + '多财善贾' => ' duō cái shàn gǔ', + '攀花折柳' => ' pān huā shé liǔ', + '攀藤揽葛' => ' pān téng lǎn gě', + '庞眉白发' => ' páng méi bái fà', + '引以为荣' => ' yǐn yǐ wéi róng', + '引吭高歌' => ' yǐn háng gāo gē', + '度德量力' => ' duó dé liàng lì', + '庞眉皓发' => ' páng méi hào fà', + '发引千钧' => ' fà yǐn qiān jūn', + '南郭处士' => ' nán guō chǔ shì', + '费尽心血' => ' fèi jìn xīn xuè', + '飞将数奇' => ' fēi jiàng shù jī', + '非分之财' => ' fēi fèn zhī cái', + '方正不阿' => ' fāng zhèng bù ē', + '暮暮朝朝' => ' mù mù zhāo zhāo', + '方差分析' => ' fāng chā fēn xī', + '反应迅速' => ' fǎn yìng xùn sù', + '不遗寸长' => ' bù yí cùn cháng', + '暴腮龙门' => ' pù sāi lóng mén', + '七返还丹' => ' qī fǎn huán dān', + '告朔饩羊' => ' gù shuò xì yáng', + '麦丘之祝' => ' mài qiū zhī zhù', + '漂泊无定' => ' piāo bó wú dìng', + '斗榫合缝' => ' dǒu sǔn hé fèng', + '古为今用' => ' gǔ wéi jīn yòng', + '带薪休假' => ' dài xīn xiū jià', + '分内之事' => ' fèn nèi zhī shì', + '洛阳才子' => ' luò yáng cái zǐ', + '马咽车阗' => ' mǎ yān chē tián', + '买卖合同' => ' mǎi mài hé tong', + '谩辞哗说' => ' màn cí huá shuō', + '东西易面' => ' dōng xi yì miàn', + '更仆难尽' => ' gèng pú nán jìn', + '嗜血杆菌' => ' shì xuè gǎn jūn', + '更难仆数' => ' gēng nán pú shù', + '满堂喝彩' => ' mǎn táng hè cǎi', + '各自为政' => ' gè zì wéi zhèng', + '尨眉皓发' => ' mánɡ méi hào fà', + '各取所长' => ' gè qǔ suǒ cháng', + '毛发之功' => ' máo fà zhī gōng', + '东歪西倒' => ' dōng wāi xī dǎo', + '东踅西倒' => ' dōng xué xī dǎo', + '电子设备' => ' diàn zǐ shè bèi', + '弱不禁风' => ' ruò bù jīn fēng', + '电子词典' => ' diàn zǐ cí diǎn', + '君子之交' => ' jūn zǐ zhī jiāo', + '铺眉苫眼' => ' pū méi shàn yǎn', + '断子绝孙' => ' duàn zǐ jué sūn', + '冬裘夏葛' => ' dōng qiú xià gě', + '披发缨冠' => ' pī fā yīng guàn', + '和睦相处' => ' hé mù xiāng chǔ', + '独有千秋' => ' dú yòu qiān qiū', + '睹物兴情' => ' dǔ wù xīng qíng', + '骈拇枝指' => ' pián mǔ zhī zhǐ', + '读书种子' => ' dú shū zhǒng zǐ', + '和尚打伞' => ' hé shang dǎ sǎn', + '否往泰来' => ' pǐ wǎng tài lái', + '漂母进饭' => ' piāo mǔ jìn fàn', + '强词夺理' => ' qiǎng cí duó lǐ', + '否终复泰' => ' pǐ zhōng fù tài', + '否终则泰' => ' pǐ zhōng zé tài', + '斗酒学士' => ' dǒu jiǔ xué shì', + '有头有尾' => ' yǒu tóu yǒu wěi', + '一言中的' => ' yī yán zhōng dì', + '度己以绳' => ' duó jǐ yǐ shéng', + '心驰魏阙' => ' xīn chí wèi què', + '间接宾语' => ' jiàn jiē bīn yǔ', + '间不容发' => ' jiān bù róng fà', + '开发银行' => ' kāi fā yín háng', + '开卷有益' => ' kāi juàn yǒu yì', + '闭卷考试' => ' bì juàn kǎo shì', + '无为自成' => ' wú wéi zì chéng', + '整齐划一' => ' zhěng qí huá yī', + '这还了得' => ' zhè hái liǎo dé', + '钻故纸堆' => ' zuàn gù zhǐ duī', + '敷衍了事' => ' fū yǎn liǎo shì', + '晏子春秋' => ' yàn zǐ chūn qīu', + '寻行数墨' => ' xún háng shǔ mò', + '压倒元白' => ' yā dǎo yuán bái', + '压卷之作' => ' yā juàn zhī zuò', + '燕岱之石' => ' yān dài zhī shí', + '言颠语倒' => ' yán diān yǔ dǎo', + '偃革为轩' => ' yǎn gé wéi xuān', + '酸不溜秋' => ' suān bu līu qīu', + '无为而成' => ' wú wéi ér chéng', + '无声无臭' => ' wú shēng wú xiù', + '炫石为玉' => ' xuàn shí wéi yù', + '离子交换' => ' lí zǐ jiāo huàn', + '相与为一' => ' xiāng yǔ wéi yī', + '长安大学' => ' cháng ān dà xué', + '倒果为因' => ' dào guǒ wéi yīn', + '校园歌曲' => ' xiào yuán gē qǔ', + '斜纹软呢' => ' xié wén ruǎn ní', + '胁肩累足' => ' xié jiān lěi zú', + '数珠念佛' => ' shǔ zhū niàn fó', + '闭上嘴巴' => ' bì shang zuǐ bā', + '随声附和' => ' suí shēng fù hè', + '舞衫歌扇' => ' wǔ shān gē shàn', + '恶恶从短' => ' wù wù cóng duǎn', + '无缝天衣' => ' wú féng tiān yī', + '无间是非' => ' wú jiàn shì fēi', + '无尽无穷' => ' wú jìn wú qióng', + '乌面鹄形' => ' wū miàn hú xíng', + '阿里山乡' => ' a lǐ shān xiāng', + '阿谀奉承' => ' ē yú fèng chéng', + '长途跋涉' => ' cháng tú bá shè', + '眼观六路' => ' yǎn guān liù lù', + '都会传奇' => ' dū huì chuán qí', + '长期以来' => ' cháng qī yǐ lái', + '明智之举' => ' míng zhì zhī jǔ', + '针线活儿' => ' zhēn xiàn huó r', + '信以为真' => ' xìn yǐ wéi zhēn', + '兴微继绝' => ' xīng wēi jì jué', + '量子力学' => ' liàng zǐ lì xué', + '量力而为' => ' liàng lì ér wéi', + '行侠好义' => ' xíng xiá hào yì', + '兴云致雨' => ' xīng yún zhì yǔ', + '袖里乾坤' => ' xiù lǐ qián kūn', + '雪山太子' => ' xuě shān tài zǐ', + '宿雨餐风' => ' xiǔ yǔ cān fēng', + '花花公子' => ' huā huā gōng zǐ', + '花旗银行' => ' huā qí yín háng', + '褚小杯大' => ' zhǔ xiǎo bēi dà', + '犹未为晚' => ' yóu wèi wéi wǎn', + '狼号鬼哭' => ' láng háo guǐ kū', + '三更半夜' => ' sān gēng bàn yè', + '属垣有耳' => ' zhǔ yuán yǒu ěr', + '物资供应' => ' wù zī gōng yìng', + '形式逻辑' => ' xíng shì luó ji', + '省身克己' => ' xǐng shēn kè jǐ', + '逻辑演算' => ' luó ji yǎn suàn', + '都市传奇' => ' dū shì chuán qí', + '适度微调' => ' shì dù wēi tiáo', + '佛蒙特州' => ' fó méng tè zhōu', + '偃武兴文' => ' yǎn wǔ xīng wén', + '逼人太甚' => ' bī rén tài shèn', + '进退为难' => ' jìn tuì wéi nán', + '曲终奏雅' => ' qǔ zhōng zòu yǎ', + '曲肱而枕' => ' qǔ gōng ér zhěn', + '燕跃鹄踊' => ' yàn yuè hú yǒng', + '心在魏阙' => ' xīn zài wèi què', + '兴如嚼蜡' => ' xìng rú jiáo là', + '重码词频' => ' chóng mǎ cí pín', + '性别差异' => ' xìng bié chā yì', + '日本银行' => ' rì běn yín háng', + '兴讹造讪' => ' xīng é zào shàn', + '日电电子' => ' rì diàn diàn zǐ', + '兴废继绝' => ' xīng fèi jì jué', + '兴利除害' => ' xīng lì chú hài', + '键盘乐器' => ' jiàn pán yuè qì', + '倒买倒卖' => ' dǎo mǎi dǎo mài', + '相女配夫' => ' xiàng nǚ pèi fū', + '以水济水' => ' yǐ shuǐ jǐ shuǐ', + '蓬头散发' => ' péng tóu sàn fà', + '洋里洋气' => ' yáng li yáng qì', + '衣锦荣归' => ' yì jǐn róng guī', + '处世之道' => ' chǔ shì zhī dào', + '人模狗样' => ' rén mú gǒu yàng', + '人情味儿' => ' rén qíng wèi ér', + '未卜先知' => ' wèi bǔ xiān zhī', + '蔚为大观' => ' wèi wéi dà guān', + '亹亹不倦' => ' tān wěi bù juàn', + '引以为鉴' => ' yǐn yǐ wéi jiàn', + '一曲阳关' => ' yī qǔ yáng guān', + '著书立说' => ' zhù shū lì shuō', + '应付票据' => ' yìng fù piào jù', + '处世原则' => ' chǔ shì yuán zé', + '交通阻塞' => ' jiāo tōng zǔ sè', + '鹰觑鹘望' => ' yīng qù hú wàng', + '亚曼牙乡' => ' yà màn yá xiāng', + '华纳兄弟' => ' huà nà xīong dì', + '用词不当' => ' yòng cí bù dàng', + '一重一掩' => ' yī chóng yī yǎn', + '以毛相马' => ' yǐ máo xiàng mǎ', + '庄稼户儿' => ' zhuāng jia hù r', + '轻浪浮薄' => ' qīng làng fú bó', + '一叶扁舟' => ' yī yè piān zhōu', + '认识不能' => ' rèn shi bù néng', + '以人为鉴' => ' yǐ rén wéi jiàn', + '更仆难数' => ' gēng pú nán shǔ', + '摇滚音乐' => ' yáo gǔn yīn yuè', + '瑶台银阙' => ' yáo tái yín què', + '鹞子翻身' => ' yào zǐ fān shēn', + '辐射对称' => ' fú shè duì chèn', + '轻嘴薄舌' => ' qīng zuǐ bó shé', + '以规为瑱' => ' yǐ guī wéi tiàn', + '异常处理' => ' yì cháng chǔ lǐ', + '誓死不降' => ' shì sǐ bù xiáng', + '占为己有' => ' zhàn wéi jǐ yǒu', + '遗臭万载' => ' yí chòu wàn zǎi', + '赶尽杀绝' => ' gǎn jìn shā jué', + '走漏消息' => ' zǒu lòu xiāo xi', + '贸易顺差' => ' mào yì shùn chā', + '买椟还珠' => ' mǎi dú huán zhū', + '二重母音' => ' èr chóng mǔ yīn', + '有的放矢' => ' yǒu dì fàng shǐ', + '相差无几' => ' xiāng chā wú jǐ', + '长途汽车' => ' cháng tú qì chē', + '人鱼小姐' => ' rén yú xiǎo jie', + '朝鲜字母' => ' cháo xiǎn zì mǔ', + '人谁无过' => ' rén shéi wú guò', + '朝闻夕改' => ' zhāo wén xī gǎi', + '褎然举首' => ' yòu rán jǔ shǒu', + '燕子衔食' => ' yàn zǐ xián shí', + '燕昭好马' => ' yān zhāo hǎo mǎ', + '数码相机' => ' shù mǎ xiàng jī', + '长足进步' => ' cháng zú jìn bù', + '一坐尽惊' => ' yī zuò jìn jīng', + '假假若是' => ' jiǎ jià ruò shì', + '值得敬佩' => ' zhí de jìng pèi', + '夕惕朝乾' => ' xī tì zhāo qián', + '蹊田夺牛' => ' xī tián duó niú', + '斗筲之器' => ' dǒu shāo zhī qì', + '借花献佛' => ' jiè huā xiàn fó', + '借腹生子' => ' jiè fù shēng zǐ', + '先自隗始' => ' xiān zì wěi shǐ', + '一坐尽倾' => ' yī zuò jìn qīng', + '朝阳地区' => ' zhāo yáng dì qū', + '杏仁豆腐' => ' xìng rén dòu fu', + '朝朝暮暮' => ' zhāo zhāo mù mù', + '有借无还' => ' yǒu jiè wú huán', + '交通堵塞' => ' jiāo tōng dǔ sè', + '一朝千里' => ' yī zhāo qiān lǐ', + '处之泰然' => ' chǔ zhī tài rán', + '饮马投钱' => ' yìn mǎ tóu qián', + '朝乾夕惕' => ' zhāo qián xī tì', + '一朝之忿' => ' yī zhāo zhī fèn', + '朝日新闻' => ' zhāo rì xīn wén', + '什么时候' => ' shén me shí hòu', + '一掷乾坤' => ' yī zhì qián kūn', + '行为主义' => ' xíng wéi zhǔ yì', + '什么地方' => ' shén me dì fang', + '朝气蓬勃' => ' zhāo qì péng bó', + '什锦果盘' => ' shí jǐn guǒ pán', + '处事原则' => ' chǔ shì yuán zé', + '朝秦暮楚' => ' zhāo qín mù chǔ', + '朝花夕拾' => ' zhāo huā xī shī', + '朝过夕改' => ' zhāo guò xī gǎi', + '度长絜大' => ' dù cháng xié dà', + '逆施倒行' => ' nì shī dǎo xíng', + '敷衍搪塞' => ' fū yǎn táng sè', + '且住为佳' => ' qiě zhù wéi jiā', + '倒三颠四' => ' dǎo sān diān sì', + '日省月试' => ' rì xǐng yuè shì', + '除害兴利' => ' chú hài xīng lì', + '重熙累绩' => ' chóng xī lěi jì', + '心神不属' => ' xīn shén bù zhǔ', + '应急措施' => ' yìng jí cuò shī', + '日朘月削' => ' rì juān yuè xuē', + '心急火燎' => ' xīn jí huǒ liǎo', + '措置得当' => ' cuò zhì dé dàng', + '日省月修' => ' rì xǐng yuè xiū', + '日长似岁' => ' rì cháng sì suì', + '心宽体胖' => ' xīn kuān tǐ pán', + '只说不做' => ' zhī shuō bù zuò', + '存亡未卜' => ' cún wáng wèi bǔ', + '只言片语' => ' zhī yán piàn yǔ', + '乾乾翼翼' => ' qián qián yì yì', + '切树倒根' => ' qiē shù dǎo gēn', + '各尽所能' => ' gè jìn suǒ néng', + '琴瑟失调' => ' qín sè shī tiáo', + '寝丘之志' => ' qǐn qiū zhī zhì', + '千磨百折' => ' qiān mó bǎi shé', + '应急出口' => ' yìng jí chū kǒu', + '反动分子' => ' fǎn dòng fèn zǐ', + '敲骨剥髓' => ' qiāo gǔ bāo suǐ', + '成佛作祖' => ' chéng fó zuò zǔ', + '殚诚毕虑' => ' dān chéng bì lǜ', + '三尺童子' => ' sān chǐ tóng zǐ', + '青山一发' => ' qīng shān yī fà', + '千载一弹' => ' qiān zǎi yī dàn', + '另辟蹊径' => ' lìng pì xī jìng', + '合众为一' => ' hé zhòng wéi yī', + '危如累卵' => ' wēi rú lěi luǎn', + '重起炉灶' => ' chóng qǐ lú zào', + '成吉思汗' => ' chéng jí sī hán', + '德薄能鲜' => ' dé bó néng xiǎn', + '重熙累叶' => ' chóng xī lěi yè', + '箪食壶浆' => ' dān sì hú jiāng', + '恶名昭著' => ' è míng zhāo zhù', + '重纰貤缪' => ' chóng pī yí miù', + '危若朝露' => ' wēi ruò zhāo lù', + '合同各方' => ' hé tong gè fāng', + '日削月朘' => ' rì xuē yuè juān', + '儋石之储' => ' dàn shí zhī chǔ', + '微电子学' => ' wēi diàn zǐ xué', + '大局为重' => ' dà jú wéi zhòng', + '千载一会' => ' qiān zǎi yī huì', + '重规袭矩' => ' chóng guī xí jǔ', + '肉山脯林' => ' ròu shān fǔ lín', + '轻财好义' => ' qīng cái hào yì', + '人自为战' => ' rén zì wéi zhàn', + '应对如流' => ' yìng duì rú liú', + '古典音乐' => ' gǔ diǎn yīn yuè', + '青灯古佛' => ' qīng dēng gǔ fó', + '洒扫应对' => ' sǎ sào yìng duì', + '口干舌燥' => ' kǒu gān shé zào', + '啛啛喳喳' => ' cuì cuì chā chā', + '重规沓矩' => ' chóng guī tà jǔ', + '千载一时' => ' qiān zǎi yī shí', + '处理程序' => ' chǔ lǐ chéng xù', + '汝成人耶' => ' nu cheng ren ye', + '淡然置之' => ' dàn rán zhì zhī', + '黑更半夜' => ' hēi gēng bàn yè', + '日以为常' => ' rì yǐ wéi cháng', + '口不应心' => ' kǒu bù yìng xīn', + '重理旧业' => ' chóng lǐ jiù yè', + '千载难遇' => ' qiān zǎi nán yù', + '所作所为' => ' suǒ zuò suǒ wéi', + '重新组合' => ' chóng xīn zǔ hé', + '所向披靡' => ' suǒ xiàng pī mǐ', + '道在人为' => ' dào zài rén wéi', + '应接不暇' => ' yìng jiē bù xiá', + '大事铺张' => ' dà shì pū zhāng', + '曲学诐行' => ' qǔ xué hǎo xíng', + '切近的当' => ' qiē jìn de dāng', + '攒锋聚镝' => ' cuán fēng jù dí', + '倒因为果' => ' dǎo yīn wéi guǒ', + '代表大会' => ' dài biǎo dà huì', + '爱乐乐团' => ' ài yuè yuè tuán', + '词穷理尽' => ' cí qióng lǐ jìn', + '塞翁之马' => ' sài wēng zhī mǎ', + '出处进退' => ' chū chǔ jìn tuì', + '敲诈勒索' => ' qiāo zhà lè suǒ', + '出没不常' => ' chū mò bù cháng', + '大相国寺' => ' dà xiàng guó sì', + '情至意尽' => ' qíng zhì yì jìn', + '箪食瓢饮' => ' dān sì piáo yǐn', + '了不可见' => ' liǎo bù kě jiàn', + '累累如珠' => ' lěi lěi rú zhū', + '横无忌惮' => ' hèng wú jì dàn', + '才轻德薄' => ' cái qīng dé bó', + '朝齑暮盐' => ' zhāo jī mù yán', + '才夸八斗' => ' cái kuā bā dǒu', + '累块积苏' => ' lěi kuài jī sū', + '老师宿儒' => ' lǎo shī xiǔ rú', + '称心如意' => ' chèn xīn rú yì', + '稻荷寿司' => ' dào hè shòu sī', + '澄沙汰砾' => ' dèng shā tài lì', + '财竭力尽' => ' cái jié lì jìn', + '情见力屈' => ' qíng xiàn lì qū', + '重游故地' => ' chóng yóu gù dì', + '将伯之呼' => ' qiāng bó zhī hū', + '触目兴叹' => ' chù mù xīng tàn', + '抽筋剥皮' => ' chōu jīn bāo pí', + '千金之子' => ' qiān jīn zhī zǐ', + '复兴时代' => ' fù xīng shí dài', + '求神问卜' => ' qiú shén wèn bǔ', + '累苏积块' => ' lěi sū jī kuài', + '结核杆菌' => ' jié hé gǎn jūn', + '瞪目哆口' => ' dèng mù chǐ kǒu', + '互为表里' => ' hù wéi biǎo lǐ', + '精疲力尽' => ' jīng pí lì jìn', + '累计折旧' => ' lěi jì zhé jiù', + '朝发夕至' => ' zhāo fā xī zhì', + '壶里乾坤' => ' hú lǐ qián kūn', + '粘皮著骨' => ' nián pí zhù gǔ', + '窝阔台汗' => ' wō kuò tái hán', + '互教互学' => ' hù jiāo hù xué', + '昭德塞违' => ' zhāo dé sè wéi', + '积德累功' => ' jī dé lěi gōng', + '澜倒波随' => ' lán dǎo bō suí', + '纷至沓来' => ' fēn zhì tà lái', + '老白干儿' => ' lǎo bái gān ér', + '出处殊途' => ' chū chǔ shū tú', + '笑口弥勒' => ' xiào kǒu mí lè', + '任人摆布' => ' rèn rén bǎi bù', + '横蛮无理' => ' hèng mán wú lǐ', + '热核反应' => ' rè hé fǎn yìng', + '触处机来' => ' chù chǔ jī lái', + '强食自爱' => ' qiǎng shí zì ài', + '倒绷孩儿' => ' dào bēng hái ér', + '性别角色' => ' xìng bié jué sè', + '苫眼铺眉' => ' shān yǎn pū méi', + '淡然处之' => ' dàn rán chǔ zhī', + '人民公仆' => ' rén mín gōng pú', + '求过于供' => ' qiú guò yú gòng', + '陈力就列' => ' chén lì jiù liè', + '求神拜佛' => ' qiú shén bài fó', + '泣数行下' => ' qì shù háng xià', + '应用物理' => ' yìng yòng wù lǐ', + '赤绳系足' => ' chì shéng jì zú', + '同归于尽' => ' tóng guī yú jìn', + '半夜三更' => ' bàn yè sān gēng', + '处尊居显' => ' chǔ zūn jū xiǎn', + '曲眉丰颊' => ' qǔ méi fēng jiá', + '尺二冤家' => ' chǐ èr yuān jia', + '思觉失调' => ' sī jué shī tiáo', + '扎实推进' => ' zhā shi tuī jìn', + '千里之志' => ' qiān lǐ zhī zhì', + '强自取折' => ' qiáng zì qǔ shé', + '重足累息' => ' chóng zú lèi xī', + '称心满意' => ' chèn xīn mǎn yì', + '原子爆弹' => ' yuán zǐ bào dàn', + '强得易贫' => ' qiǎng dé yì pín', + '应机立断' => ' yìng jī lì duàn', + '情见乎辞' => ' qíng xiàn hū cí', + '厚死薄生' => ' hòu sǐ bó shēng', + '三老五更' => ' sān lǎo wǔ gēng', + '翘首企足' => ' qiáo shǒu qǐ zú', + '强而后可' => ' qiǎng ér hòu kě', + '鹑衣鹄面' => ' chún yī hú miàn', + '瞪眼咋舌' => ' dèng yǎn zé shé', + '吃着不尽' => ' chī zhuó bù jìn', + '倾心尽力' => ' qīng xīn jìn lì', + '请自隗始' => ' qǐng zì wěi shǐ', + '抵死谩生' => ' dǐ sǐ màn shēng', + '穷不失义' => ' qióng bù shī yì', + '应县木塔' => ' yìng xiàn mù tǎ', + '反兴奋剂' => ' fǎn xīng fèn jì', + '反动势力' => ' fǎn dòng shì li', + '诞谩不经' => ' dàn màn bù jīng', + '人事不省' => ' rén shì bù xǐng', + '半身不遂' => ' bàn shēn bù suí', + '后翻筋斗' => ' hòu fān jīn dǒu', + '乐尽哀生' => ' lè jìn āi shēng', + '怒涛澎湃' => ' nù tāo péng pài', + '精义入神' => ' jing yi ru shen', + '见义敢为' => ' jiàn yì gǎn wéi', + '谨毛失貌' => ' jǐn máo shī mào', + '尽其所能' => ' jìn qí suǒ néng', + '天竺牡丹' => ' tiān zhú mǔ dan', + '进退出处' => ' jìn tuì chū chǔ', + '经纶济世' => ' jing lun ji shi', + '经史百子' => ' jīng shǐ bǎi zǐ', + '将门虎子' => ' jiàng mén hǔ zǐ', + '奏鸣曲式' => ' zòu míng qǔ shì', + '浇风薄俗' => ' jiāo fēng bó sú', + '还我河山' => ' huán wǒ hé shān', + '积以为常' => ' jī yǐ wéi cháng', + '举世混浊' => ' jǔ shì hún zhuó', + '娱乐场所' => ' yú lè cháng suǒ', + '火急火燎' => ' huǒ jí huǒ liǎo', + '倔头倔脑' => ' juè tou juè nǎo', + '婚生子女' => ' hūn shēng zǐ nǚ', + '多灾多难' => ' duō zāi duō nàn', + '尽付东流' => ' jìn fù dōng liú', + '太阳黑子' => ' tài yáng hēi zǐ', + '君子固穷' => ' jūn zǐ gù qióng', + '钜人长德' => ' jù rén cháng dé', + '居不重茵' => ' jū bù chóng yīn', + '捡洋落儿' => ' jiǎn yáng là ér', + '佳人薄命' => ' jiā rén bó mìng', + '鞠躬屏气' => ' jū gōng bǐng qì', + '好为人师' => ' hào wéi rén shī', + '好酒贪杯' => ' hào jiǔ tān bēi', + '好高骛远' => ' hào gāo wù yuǎn', + '如数家珍' => ' rú shǔ jiā zhēn', + '戟指嚼舌' => ' jǐ zhǐ jiáo shé', + '教书育人' => ' jiāo shū yù rén', + '举措失当' => ' jǔ cuò shī dàng', + '基因重组' => ' jī yīn chóng zǔ', + '大处着眼' => ' dà chù zhuó yǎn', + '尖嘴薄舌' => ' jiān zuǐ bó shé', + '解除合同' => ' jiě chú hé tong', + '解衣盘磅' => ' jiě yī pán páng', + '教一识百' => ' jiāo yī shí bǎi', + '嚼铁咀金' => ' jiáo tiě jǔ jīn', + '魂飞魄丧' => ' hún fēi pò sāng', + '君子协定' => ' jūn zǐ xié dìng', + '久要不忘' => ' jiǔ yāo bù wàng', + '流血漂橹' => ' liú xiě piāo lǔ', + '大便干燥' => ' dà biàn gān zào', + '积功兴业' => ' jī gōng xīng yè', + '急公好施' => ' jí gōng hào shī', + '疾风甚雨' => ' jí fēng shèn yǔ', + '抉奥阐幽' => ' jué ào chǎn yōu', + '激薄停浇' => ' jī bó tíng jiāo', + '饥寒交切' => ' jī hán jiāo qiē', + '吐蕃王朝' => ' tǔ bō wáng cháo', + '鼓衰力尽' => ' gǔ shuāi lì jìn', + '豁然省悟' => ' huò rán xǐng wù', + '黏黏糊糊' => ' nián nián hū hū', + '年谊世好' => ' nián yì shì hào', + '康巴藏区' => ' kāng bā zàng qū', + '宁折不弯' => ' nìng zhé bù wān', + '扼腕长叹' => ' è wàn cháng tàn', + '廊坊地区' => ' láng fáng dì qū', + '峨峨汤汤' => ' é é shāng shāng', + '夺人所好' => ' duó rén suǒ hào', + '计尽力穷' => ' jì jìn lì qióng', + '积累经验' => ' jī lěi jīng yàn', + '开户银行' => ' kāi hù yín háng', + '回天倒日' => ' huí tiān dǎo rì', + '看家本事' => ' kān jiā běn shì', + '回干就湿' => ' huí gān jiù shī', + '看守内阁' => ' kān shǒu nèi gé', + '子宫颈癌' => ' zǐ gōng jǐng ái', + '黄口孺子' => ' huáng kǒu rú zǐ', + '恪尽职守' => ' kè jìn zhí shǒu', + '没齿难忘' => ' mò chǐ nán wàng', + '还珠买椟' => ' huán zhū mǎi dú', + '吉凶未卜' => ' jí xiōng wèi bǔ', + '卷甲韬戈' => ' juàn jiǎ tāo gē', + '倔强倨傲' => ' jué jiàng jù ào', + '祸为福先' => ' huò wéi fú xiān', + '箕山之志' => ' jī shān zhī zhì', + '计穷虑尽' => ' jì qióng lǜ jìn', + '句子成分' => ' jù zi chéng fèn', + '计穷力尽' => ' jì qióng lì jìn', + '极情尽致' => ' jí qíng jìn zhì', + '积年累岁' => ' jī nián lěi suì', + '间不容息' => ' jiàn bù róng xī', + '好吃懒做' => ' hào chī lǎn zuò', + '守正不阿' => ' shǒu zhèng bù ē', + '会计核算' => ' kuài jì hé suàn', + '花朝月夜' => ' huā zhāo yuè yè', + '哗世取名' => ' huá shì qǔ míng', + '哗世动俗' => ' huá shì dòng sú', + '画蛇著足' => ' huà shé zhuó zú', + '化合反应' => ' huà hé fǎn yìng', + '红颜白发' => ' hóng yán bái fà', + '花攒锦聚' => ' huā cuán jǐn jù', + '花簇锦攒' => ' huā cù jǐn cuán', + '胡作乱为' => ' hú zuò luàn wéi', + '淮橘为枳' => ' huái jú wéi zhǐ', + '塞翁失马' => ' sài wēng shī mǎ', + '快心遂意' => ' kuài xīn suí yì', + '字里行间' => ' zì lǐ háng jiān', + '揆理度情' => ' kuí lǐ duó qíng', + '揆情度理' => ' kuí qíng duó lǐ', + '花攒锦簇' => ' huā cuán jǐn cù', + '口轻舌薄' => ' kǒu qīng shé bó', + '好学不倦' => ' hào xué bù juàn', + '怀敌附远' => ' huái dí fù yuǎn', + '苦尽甜来' => ' kǔ jìn tián lái', + '刿鉥肝肾' => ' guì xù gān shèn', + '合同管理' => ' hé tong guǎn lǐ', + '累教不改' => ' lěi jiào bù gǎi', + '横行无忌' => ' héng xíng wú jì', + '横行不法' => ' héng xíng bù fǎ', + '擂天倒地' => ' léi tiān dǎo dì', + '累土至山' => ' lěi tǔ zhì shān', + '鸿鹄之志' => ' hóng hú zhī zhì', + '累足成步' => ' lěi zú chéng bù', + '客户应用' => ' kè hù yìng yòng', + '李广不侯' => ' lǐ guǎng bù hòu', + '口血未干' => ' kǒu xuè wèi gān', + '历尽艰辛' => ' lì jìn jiān xīn', + '河梁之谊' => ' hé liáng zhì yí', + '合两为一' => ' hé liǎng wéi yī', + '赫赫之光' => ' hè hè zhì guāng', + '横倒竖卧' => ' héng dǎo shù wò', + '历精为治' => ' lì jīng wéi zhì', + '洪炉燎发' => ' hóng lú liáo fà', + '腊尽春回' => ' là jìn chūn huí', + '礼让为国' => ' lǐ ràng wéi guó', + '刿心鉥肾' => ' guì xīn xù shèn', + '间接推理' => ' jiàn jiē tuī lǐ', + '量力度德' => ' liàng lì duó dé', + '宁左勿右' => ' nìng zuǒ wù yòu', + '宁缺勿滥' => ' nìng quē wù làn', + '宁缺毋滥' => ' nìng quē wú làn', + '鬼蜮伎俩' => ' guǐ yù jì liǎng', + '图像处理' => ' tú xiàng chǔ lǐ', + '国定假日' => ' guó dìng jià rì', + '敛色屏气' => ' liǎn sè bǐng qì', + '含混不清' => ' hán hún bù qīng', + '过为已甚' => ' guò wéi yǐ shèn', + '察微知著' => ' chá wēi zhī zhù', + '行间字里' => ' háng jiān zì lǐ', + '对称破缺' => ' duì chèn pò quē', + '空调机组' => ' kōng tiáo jī zǔ', + '还珠返璧' => ' huán zhū fǎn bì', + '女性厌恶' => ' nǔ: xìng yàn wù', + '大兴安岭' => ' dà xīng ān lǐng', + '好久不见' => ' hǎo jǐu bu jiàn', + '大腹便便' => ' dà fù pián pián', + '礼为情貌' => ' lǐ wéi qíng mào', + '里挑外撅' => ' lǐ tiǎo wài juē', + '桂折兰摧' => ' guì shé lán cuī', + '领导班子' => ' líng dǎo bān zǐ', + '专心一意' => ' zhuān xīn yī yì', + '劣迹昭着' => ' liè jì zhāo zhe', + '劣迹昭著' => ' liè jì zhāo zhù', + '裂眦嚼齿' => ' liè zì jiáo chǐ', + '临敌易将' => ' lín dí yì jiàng', + '射频干扰' => ' shè pín gān rǎo', + '临难不恐' => ' lín nàn bù kǒng', + '凌波仙子' => ' líng bō xiān zǐ', + '管理会计' => ' guǎn lǐ kuài jì', + '好善乐施' => ' hào shàn lè shī', + '冠绝一时' => ' guàn jué yī shí', + '冠屦倒施' => ' guàn jù dǎo shī', + '对牛弹琴' => ' duì niú tán qín', + '麟子凤雏' => ' lín zǐ fèng chú', + '毫无用处' => ' háo wú yòng chu', + '规旋矩折' => ' guī xuán jǔ shé', + '过而能改' => ' guò ér néng gǎi', + '立身处世' => ' lì shēn chǔ shì', + '滔滔不尽' => ' tāo tāo bù jìn', + '一发千钧' => ' yī fà qiān jūn', + '敏而好学' => ' mǐn ér hào xué', + '普什图语' => ' pǔ shí tú yǔ', + '的一确二' => ' dí yī què èr', + '柴立不阿' => ' chái lì bù ē', + '魂不附体' => ' hún bù fù tǐ', + '业余爱好' => ' yè yú ài hào', + '无与为比' => ' wú yǔ wéi bǐ', + '一鼻子灰' => ' yī bí zǐ huī', + '走背字儿' => ' zǒu bèi zì r', + '佛洛伊德' => ' fó luò yī dé', + '易地而处' => ' yì dì ér chǔ', + '呆似木鸡' => ' dāi sì mù jī', + '佛罗里达' => ' fó luó lǐ dá', + '偃旗仆鼓' => ' yǎn qí pú gǔ', + '悉索薄赋' => ' xī suǒ bó fù', + '太子河区' => ' tài zǐ hé qū', + '值得一提' => ' zhí de yī tí', + '贝塔粒子' => ' bèi tǎ lì zǐ', + '四季豆腐' => ' sì jì dòu fu', + '薄胎瓷器' => ' bó tāi cí qì', + '低音喇叭' => ' dī yīn lǎ ba', + '巴勒斯坦' => ' bā lè sī tǎn', + '一字不差' => ' yī zì bù chā', + '可疑分子' => ' kě yí fèn zǐ', + '豁达大度' => ' huò dá dà dù', + '如金似玉' => ' rú jīn sì yù', + '参差不一' => ' cēn cī bù yī', + '暴衣露盖' => ' pù yī lù gài', + '自给有余' => ' zì jǐ yǒu yú', + '耶鲁大学' => ' yē lǔ dà xué', + '打闷葫芦' => ' dǎ mèn hú lu', + '咸丝丝儿' => ' xián sī sī r', + '塞哥维亚' => ' sè gē wéi yà', + '仆仆亟拜' => ' pú pú jí bài', + '仆仆道途' => ' pú pú dào tú', + '赫鲁雪夫' => ' hè lǔ xuě fu', + '妇人孺子' => ' fù rén rú zǐ', + '夫子自道' => ' fū zǐ zì dào', + '萨哈罗夫' => ' sà hǎ luó fū', + '萨哈诺夫' => ' sà hǎ nuò fū', + '赛普勒斯' => ' sài pǔ lè sī', + '基本粒子' => ' jī běn lì zǐ', + '大头娃娃' => ' dà tóu wá wa', + '达到目的' => ' dá dào mù dì', + '故甚其词' => ' gù shèn qí cí', + '咖啡馆儿' => ' kā fēi guǎn r', + '如鱼似水' => ' rú yú sì shuǐ', + '指鹿为马' => ' zhǐ lù wéi mǎ', + '红得发紫' => ' hóng de fā zǐ', + '积日累久' => ' jī rì lěi jiǔ', + '卡文迪什' => ' kǎ wén dí shí', + '济济一堂' => ' jǐ jǐ yī táng', + '否极泰来' => ' pǐ jí tài lái', + '如拾地芥' => ' rú shí dì jiè', + '湮没无闻' => ' yān mò wú wén', + '不尽人意' => ' bù jìn rén yì', + '胡作胡为' => ' hú zuò hú wéi', + '济宁地区' => ' jǐ níng dì qū', + '左宜右有' => ' zuǒ yí yòu fú', + '坐地自划' => ' zuò dì zì huá', + '百思莫解' => ' bǎi sī mò jiě', + '孤行一意' => ' gū xíng yī yì', + '眦裂发指' => ' zì liè fà zhǐ', + '积时累日' => ' jī shí lěi rì', + '厚古薄今' => ' hòu gǔ bó jīn', + '累及无辜' => ' lěi jí wú gū', + '不可究诘' => ' bù kě jiū jié', + '析骸易子' => ' xī hái yì zǐ', + '呼来喝去' => ' hū lái hè qù', + '大雅君子' => ' dà yǎ jūn zǐ', + '葫芦依样' => ' hú lu yī yàng', + '模糊数学' => ' mó hu shù xué', + '击石弹丝' => ' jī shí tán sī', + '模糊不清' => ' mó hu bù qīng', + '如痴似醉' => ' rú chī sì zuì', + '一丘之貉' => ' yī qiū zhī hé', + '孤文只义' => ' gū wén zhī yì', + '半部论语' => ' bàn bù lún yǔ', + '咭咭呱呱' => ' jī jī guā guā', + '一暴十寒' => ' yī pù shí hán', + '白日衣绣' => ' bái rì yì xiù', + '百堕俱举' => ' bǎi huī jù jǔ', + '人足家给' => ' rén zú jiā jǐ', + '扳不倒儿' => ' bān bù dǎo ér', + '呼幺喝六' => ' hū yāo hè liù', + '耶利米书' => ' yē lì mǐ shū', + '严了眼儿' => ' yán le yǎn r', + '字纸篓子' => ' zì zhǐ lǒu zi', + '齐眉穗儿' => ' qí méi suì r', + '婀娜多姿' => ' ē nuó duō zī', + '不绝如发' => ' bù jué rú fà', + '包袱皮儿' => ' bāo fú pí er', + '刻鹄类鹜' => ' kè hú lèi wù', + '草字头儿' => ' cǎo zì tóu r', + '库尔勒市' => ' kù ěr lè shì', + '倒打一耙' => ' dào dǎ yī pá', + '柏蒂切利' => ' bó dì qiè lì', + '漫无目的' => ' màn wú mù dì', + '负担不起' => ' fù dān bu qǐ', + '泥而不滓' => ' niè ér bù zǐ', + '凡夫俗子' => ' fán fū sú zǐ', + '刻薄寡恩' => ' kè bó guǎ ēn', + '茄子河区' => ' qié zi hé qū', + '泥多佛大' => ' ní duō fó dà', + '哈德逊河' => ' hā dé xùn hé', + '舍利子塔' => ' shè lì zi tǎ', + '离本趣末' => ' lí běn qū mò', + '心细如发' => ' xīn xì rú fà', + '阿意取容' => ' ē yì qǔ róng', + '岁聿其莫' => ' suì yù qí mù', + '聚米为谷' => ' jù mǐ wéi gǔ', + '贝尔格勒' => ' bèi ěr gé lè', + '阿赖耶识' => ' ā lài yē shí', + '合而为一' => ' hé ér wéi yī', + '何足为奇' => ' hé zú wéi qí', + '削发披缁' => ' xuē fà pī zī', + '阿世媚俗' => ' ē shì mèi sú', + '子虚乌有' => ' zǐ xū wū yǒu', + '学习目的' => ' xué xí mù dì', + '杜塞道夫' => ' dù sè dào fū', + '德布勒森' => ' dé bù lè sēn', + '须弥芥子' => ' xū mí jiè zǐ', + '泥足巨人' => ' ní zú jù rén', + '私淑弟子' => ' sī shū dì zǐ', + '搭把手儿' => ' dā bǎ shǒu r', + '子母扣儿' => ' zǐ mǔ kòu ér', + '乌德勒支' => ' wū dé lè zhī', + '巴甫洛夫' => ' bā fǔ luò fū', + '合二为一' => ' hé èr wéi yī', + '分丝析缕' => ' fēn sī xī lǚ', + '企业倒闭' => ' qǐ yè dǎo bì', + '临崖勒马' => ' lín yá lè mǎ', + '济南地区' => ' jǐ nán dì qū', + '阿谀取容' => ' ē yú qǔ róng', + '爱素好古' => ' ài sù hào gǔ', + '八字帖儿' => ' bā zì tiě ér', + '不足为法' => ' bù zú wéi fǎ', + '不足为据' => ' bù zú wéi jù', + '过一会儿' => ' guò yī huì r', + '不以为奇' => ' bù yǐ wéi qí', + '一览无遗' => ' yī lǎi wú yí', + '一心一意' => ' yī xīn yī yì', + '不足为意' => ' bù zú wéi yì', + '布鲁塞尔' => ' bù lǔ sài ěr', + '妻梅子鹤' => ' qī mén zǐ hè', + '得马折足' => ' dé mǎ shé zú', + '几何拓扑' => ' jǐ hé tuò pū', + '打马虎眼' => ' dǎ mǎ hu yǎn', + '大吃大喝' => ' dà chī dà hè', + '跗萼载韡' => ' fū è zǎi wěi', + '历历可数' => ' lì lì kě shǔ', + '嘁哩喀喳' => ' qī lǐ kā chā', + '矮子看戏' => ' ǎi zǐ kàn xì', + '粪土不如' => ' fèn tú bù rú', + '哈佛大学' => ' hā fó dà xué', + '呢喃细语' => ' ní nán xì yǔ', + '遂迷不寤' => ' suí mí bù wù', + '不足部分' => ' bù zú bù fen', + '何乐不为' => ' hé lè bù wéi', + '不以为意' => ' bù yǐ wéi yì', + '泰极而否' => ' tài jí ér pǐ', + '葛瑞格尔' => ' gě ruì gé ěr', + '毫不客气' => ' háo bù kè qi', + '曲霉毒素' => ' qǔ méi dú sù', + '大难不死' => ' dà nàn bù sǐ', + '葡萄干儿' => ' pú tao gān r', + '聱牙诘屈' => ' áo yá jié qū', + '囤积居奇' => ' tún jī jū qí', + '帕特丽夏' => ' pà tè lí xià', + '艾哈迈德' => ' aì hǎ mài dé', + '为德不卒' => ' wéi dé bù zú', + '似有如无' => ' sì yǒu rú wú', + '伺瑕抵隙' => ' sì xiá dǐ xì', + '日薄西山' => ' rì bó xī shān', + '如花似锦' => ' rú huā sì jǐn', + '鹤子梅妻' => ' hè zǐ méi qī', + '木头人儿' => ' mù tóu rén er', + '发指眦裂' => ' fà zhǐ zì liè', + '哩哩罗罗' => ' lī lī luō luō', + '骨头节儿' => ' gú tou jié ér', + '不差毫厘' => ' bù chā háo lí', + '扒耳搔腮' => ' pá ěr sāo sāi', + '撒都该人' => ' sā dū gāi rén', + '高音喇叭' => ' gāo yīn lǎ ba', + '火妻灰子' => ' huǒ qī huī zǐ', + '狗拿耗子' => ' gǒu ná hào zǐ', + '哩哩啰啰' => ' lī li luō luō', + '吉卜赛人' => ' jí bǔ sài rén', + '独辟蹊径' => ' dú pì xī jìng', + '披头散发' => ' pī tóu sàn fà', + '独山子区' => ' dú shān zǐ qū', + '号寒啼饥' => ' háo hán tí jī', + '庆父不死' => ' qìng fǔ bù sǐ', + '不可数集' => ' bù kě shuò jí', + '独具只眼' => ' dú jù zhī yǎn', + '不以为然' => ' bù yǐ wéi rán', + '厚德载福' => ' hòu dé zǎi fú', + '拉卜楞寺' => ' lā bǔ lèng sì', + '掳人勒赎' => ' lǔ rén lè shú', + '富得流油' => ' fù de líu yóu', + '好逸恶劳' => ' hào yì wù láo', + '积累基金' => ' jī lěi jī jīn', + '鼓起勇气' => ' gǔ qǐ yǒng qì', + '不是滋味' => ' bú shì zī wèi', + '助桀为恶' => ' zhù jié wéi è', + '只骑不反' => ' zhī qí bù fǎn', + '不是味儿' => ' bú shì wèi ér', + '子孝父慈' => ' zǐ xiào fù cí', + '难乎为继' => ' nán hū wéi jì', + '不拔之志' => ' bù bá zhī zhì', + '子子孙孙' => ' zǐ zǐ sūn sūn', + '蔽日干云' => ' bì rì gān yún', + '比物属事' => ' bǐ wù zhǔ shì', + '置之不顾' => ' zhì zhī bù gù', + '豁人耳目' => ' huò rén ěr mù', + '差异分析' => ' chā yì fēn xī', + '厚今薄古' => ' hòu jīn bó gǔ', + '骨头架子' => ' gú tou jià zi', + '之子于归' => ' zhī zǐ yú guī', + '好语似珠' => ' hǎo yǔ sì zhū', + '比什凯克' => ' bǐ shí kǎi kè', + '脾气暴躁' => ' pí qi bào zào', + '靡有孑遗' => ' mǐ yǒu jié yí', + '靡靡之音' => ' mǐ mǐ zhī yīn', + '背碑覆局' => ' bèi bēi fù jú', + '著于竹帛' => ' zhù yú zhú bó', + '一饮而尽' => ' yī yǐn ér jìn', + '子为父隐' => ' zǐ wéi fù yǐn', + '刿目鉥心' => ' guì mù xù xīn', + '主要目的' => ' zhǔ yào mù dì', + '墨迹未干' => ' mò jì wèi gān', + '不足为训' => ' bù zú wéi xùn', + '鲍子知我' => ' bào zǐ zhī wǒ', + '气息奄奄' => ' qì xī yān yān', + '电荷耦合' => ' diàn hè ǒu hé', + '仁义君子' => ' rén yì jūn zǐ', + '丢三落四' => ' diū sān là sì', + '原子武器' => ' yuán zǐ wǔ qì', + '不知起倒' => ' bù zhī qǐ dǎo', + '莫可究诘' => ' mò kě jiū jié', + '不切实际' => ' bù qiē shí jì', + '马萨诸塞' => ' mǎ sà zhū sài', + '互不干涉' => ' hù bù gān shè', + '吼三喝四' => ' hǒu sān hè sì', + '驽马十舍' => ' nú mǎ shí shè', + '父慈子孝' => ' fù cí zǐ xiào', + '目眦尽裂' => ' mù zì jìn liè', + '清辞丽曲' => ' qīng cí lì qǔ', + '难以为继' => ' nán yǐ wéi jì', + '温切斯特' => ' wēn qiē sī tè', + '白眼珠儿' => ' bái yǎn zhū r', + '没有意思' => ' méi yǒu yì si', + '挨打受气' => ' ái dǎ shòu qì', + '为仁不富' => ' wéi rén bù fù', + '热热闹闹' => ' rè rè nāo nao', + '安分知足' => ' ān fèn zhī zú', + '击排冒没' => ' jī pái mào mò', + '为富不仁' => ' wéi fù bù rén', + '比佛利山' => ' bǐ fó lì shān', + '挨打受骂' => ' ái dǎ shòu mà', + '匹马只轮' => ' pǐ mǎ zhī lún', + '及时处理' => ' jí shí chǔ lǐ', + '各行各业' => ' gè háng gè yè', + '只眼独具' => ' zhī yǎn dú jù', + '呢呢痴痴' => ' ní ní chī chī', + '七老八倒' => ' qī lǎo bā dǎo', + '暴衣露冠' => ' pù yī lù guàn', + '雷扎耶湖' => ' léi zhá yē hú', + '子母炸弹' => ' zǐ mǔ zhà dàn', + '日乾夕惕' => ' rì qián xī tì', + '日甚一日' => ' rì shèn yī rì', + '如履薄冰' => ' rú lǚ bó bīng', + '一朝一夕' => ' yī zhāo yī xī', + '卸磨杀驴' => ' xiè mò shā lǘ', + '朝不及夕' => ' zhāo bù jí xī', + '化腐为奇' => ' huà fǔ wéi qí', + '波流茅靡' => ' bō liú máo mǐ', + '别开一格' => ' bié kāi yí gé', + '寡凫单鹄' => ' guǎ fú dān hú', + '电子伏特' => ' diàn zǐ fú tè', + '如切如磋' => ' rú qiē rú cuō', + '否极泰回' => ' pǐ jí tài huí', + '披发左衽' => ' pī fà zuǒ rèn', + '子母炮弹' => ' zǐ mǔ pào dàn', + '白费力气' => ' bái fèi lì qi', + '如龙似虎' => ' rú lóng sì hǔ', + '彬彬济济' => ' bīn bīn jǐ jǐ', + '不可揆度' => ' bù kě kuí duó', + '呼天吁地' => ' hū tiān yù dì', + '积素累旧' => ' jī sù lěi jiù', + '含含糊糊' => ' hán hán hu hū', + '卜夜卜昼' => ' bǔ yè bǔ zhòu', + '弃甲倒戈' => ' qì jiǎ dǎo gē', + '播糠眯目' => ' bō kāng mǐ mù', + '扑杀此獠' => ' pū shā cǐ lǎo', + '不亦善夫' => ' bù yi shàn fū', + '如花似月' => ' rú huā sì yuè', + '气克斗牛' => ' qì kè dǒu niú', + '一模一样' => ' yī mú yī yàng', + '不随以止' => ' bu shui yi zi', + '一分为二' => ' yī fēn wéi èr', + '椎髻布衣' => ' zhuī jì bù yī', + '朝斯夕斯' => ' zhāo sī xī sī', + '苞苴竿牍' => ' bāo jū gān dú', + '尽力而为' => ' jìn lì ér wéi', + '积日累月' => ' jī rì lěi yuè', + '皮包骨头' => ' pí bāo gú tou', + '鼻口部分' => ' bí kǒu bù fèn', + '目空余子' => ' mù kōng yú zǐ', + '指头肚儿' => ' zhǐ tou dù er', + '青紫被体' => ' qīng zǐ pī tǐ', + '属辞比事' => ' zhǔ cí bǐ shì', + '不差毫发' => ' bù chā háo fà', + '避祸求福' => ' bì huò qiú fù', + '至矣尽矣' => ' zhì yǐ jìn yǐ', + '余勇可贾' => ' yú yǒng kě gǔ', + '史蒂文斯' => ' shǐ dì wén sī', + '积德累仁' => ' jī dé lěi rén', + '朱干玉戚' => ' zhū gān yù qī', + '宁死不屈' => ' nìng sǐ bù qū', + '母慈子孝' => ' mǔ cí zǐ xiào', + '下不为例' => ' xià bù wéi lì', + '黑芝麻糊' => ' hēi zhī ma hú', + '好问则裕' => ' hào wèn zé yù', + '属毛离里' => ' zhǔ máo lí lǐ', + '吆五喝六' => ' yāo wǔ hè liù', + '厚味腊毒' => ' hòu wèi xī dú', + '卑礼厚币' => ' bēi lǐ hòu bì', + '好善恶恶' => ' hǎo shàn wù è', + '不识起倒' => ' bù shí qǐ dǎo', + '气动葫芦' => ' qì dòng hú lu', + '激进分子' => ' jī jìn fèn zǐ', + '皮诺切特' => ' pí nuò qiē tè', + '不以为耻' => ' bù yǐ wéi chǐ', + '呱嗒板儿' => ' guā dā bǎn ér', + '宏都拉斯' => ' hóng dū lā sī', + '骑驴倒堕' => ' qí lǘ dǎo duò', + '积日累岁' => ' jī rì lěi suì', + '虎珀拾芥' => ' hǔ pò shí jiè', + '插入因子' => ' chā rù yīn zǐ', + '惠子知我' => ' huì zǐ zhī wǒ', + '如花似朵' => ' rú huā sì duǒ', + '一意孤行' => ' yī yì gū xíng', + '何所不为' => ' hé suǒ bù wéi', + '豁然大悟' => ' huò rán dà wù', + '八大胡同' => ' bā dà hú tòng', + '号啕大哭' => ' háo táo dà kū', + '自以为然' => ' zì yǐ wéi rán', + '没人味儿' => ' méi rén wèi r', + '贝克勒尔' => ' bèi kè lè ěr', + '村夫俗子' => ' cūn fū sú zǐ', + '不禁不由' => ' bù jīn bù yóu', + '德勒巴克' => ' dé lè bā kè', + '吧唧吧唧' => ' bā ji bā ji', + '第一义谛' => ' dì yī yì dì', + '嘀里嘟噜' => ' dī lǐ dū lū', + '滴滴答答' => ' dī dī dā dā', + '乐乐呵呵' => ' lè lè hē hē', + '蹀儿鸭子' => ' dié r yā zi', + '忍饥挨饿' => ' rěn jī ái è', + '遗妻弃子' => ' yí qī qì zǐ', + '七子八婿' => ' qī zǐ bā xù', + '百色起义' => ' bó sè qǐ yì', + '迪斯科吧' => ' dí sī kē bā', + '不易一字' => ' bù yì yī zì', + '迷离马虎' => ' mí lí mǎ hu', + '迷迷糊糊' => ' mí mi hū hū', + '马路牙子' => ' mǎ lù yá zǐ', + '扎尔达里' => ' zā ěr dá lǐ', + '阿多尼斯' => ' a duō ní sī', + '扎鲁特旗' => ' zā lǔ tè qí', + '提拉米苏' => ' dī lā mǐ sū', + '古希腊语' => ' gǔ xī là yǔ', + '阿弥陀佛' => ' ē mí tuó fó', + '孤立子波' => ' gū lì zǐ bō', + '格格不吐' => ' gē gē bù tǔ', + '格格不纳' => ' gē gē bù nà', + '子女玉帛' => ' zǐ nǚ yù bó', + '法不阿贵' => ' fǎ bù ē guì', + '一古脑儿' => ' yī gǔ nǎo r', + '茶叶末儿' => ' chá yè mò r', + '计日而俟' => ' jì rì ér sì', + '一字不易' => ' yī zì bù yì', + '糊糊涂涂' => ' hū hū tú tú', + '哩哩啦啦' => ' li li lā lā', + '的黎波里' => ' dì lí bō lǐ', + '莫扎里拉' => ' mò zā lǐ lā', + '那不勒斯' => ' nà bù lè sī', + '那曲地区' => ' nà qǔ dì qū', + '哪儿的话' => ' nǎ r de huà', + '嗳气呕逆' => ' ài qì ǒu nì', + '劈里啪啦' => ' pī li pā lā', + '可歌可泣' => ' kě gē kě qì', + '阿富汗语' => ' a fù hàn yǔ', + '阿得莱德' => ' a dé lái dé', + '第比利斯' => ' dì bì lì sī', + '叽哩咕噜' => ' jī li gū lū', + '阿尔泰语' => ' a ěr tài yǔ', + '阿尔瓦雷' => ' a ěr wǎ léi', + '阿尔盖达' => ' a ěr gài dá', + '勒斯波斯' => ' lè sī bō sī', + '头儿脑儿' => ' tóu r nǎo r', + '墨子泣丝' => ' mò zǐ qì sī', + '马路沿儿' => ' mǎ lù yán r', + '目无余子' => ' mù wú yú zǐ', + '霹雳啪啦' => ' pī lì pā lā', + '卡拉季奇' => ' kǎ lā jì jī', + '模模糊糊' => ' mó mó hu hū', + '彼得格勒' => ' bǐ dé gé lè', + '克拉科夫' => ' kè lā kē fū', + '克孜勒苏' => ' kè zī lè sū', + '薄物细故' => ' bó wù xì gù', + '噼里啪啦' => ' pī lǐ pā lā', + '弥勒菩萨' => ' mí lè pú sà', + '认死理儿' => ' rèn sǐ lǐ r', + '卡拉奇那' => ' kǎ lā jī nà', + '阿尔卑斯' => ' a ěr bēi sī', + '阿德莱德' => ' a dé lái dé', + '阿美尼亚' => ' a měi ní yà', + '阿德雷德' => ' a dé léi dé', + '阿加迪尔' => ' a jiā dí ěr', + '阿利坎特' => ' a lì kǎn tè', + '阿伦达尔' => ' a lún dá ěr', + '阿克伦河' => ' a kè lún hé', + '阿克苏市' => ' a kè sū shì', + '阿拉伯文' => ' a lā bó wén', + '阿摩司书' => ' a mó sī shū', + '阿美恩斯' => ' a měi ēn sī', + '卡波耶拉' => ' kǎ bō yē lā', + '喀啦喀啦' => ' kā lā kā lā', + '阿金库尔' => ' a jīn kù ěr', + '阿拉尔市' => ' a lā ěr shì', + '阿特金斯' => ' a tè jīn sī', + '批哩啪啦' => ' pī li pā la', + '鸡蛋壳儿' => ' jī dàn ké r', + '卡尔扎伊' => ' kǎ ěr zā yī', + '阿普尔顿' => ' a pǔ ěr dùn', + '疙疙瘩瘩' => ' gē gē dā dá', + '粒子物理' => ' lì zǐ wù lǐ', + '闭目塞耳' => ' bì mù sè ěr', + '阿拉法特' => ' a lā fǎ tè', + '阿尔卡特' => ' a ěr kǎ tè', + '阿里巴巴' => ' a lǐ bā bā', + '阿耳戈斯' => ' a ěr gē sī', + '阿瓦里德' => ' a wǎ lǐ dé', + '阿穆尔河' => ' a mù ěr hé', + '阿斯马拉' => ' a sī mǎ lā', + '阿斯塔纳' => ' a sī tǎ nà', + '阿丽亚娜' => ' a lì yà nà', + '打哈哈儿' => ' dǎ hā ha r', + '阿尔伯特' => ' a ěr bó tè', + '阿拉巴马' => ' a lā bā mǎ', + '阿拉塔斯' => ' a lā tǎ sī', + '阿拉米语' => ' a lā mǐ yǔ', + '阿斯伯格' => ' a sī bó gé', + '阿格尼迪' => ' a gé ní dí', + '无恶不为' => ' wú è bù wéi', + '可泣可歌' => ' kě qì kě gē', + '呵佛骂祖' => ' hē fó mà zǔ', + '阿尔萨斯' => ' a ěr sà sī', + '阿尔伯塔' => ' a ěr bó tǎ', + '与物无忤' => ' yǔ wù wú wǔ', + '阿卜杜拉' => ' a bǔ dù lā', + '阿瓦鲁阿' => ' a wǎ lǔ ā', + '双重标准' => ' shuāng chóng biāo zhǔn', + '苦不唧儿' => ' kǔ bu jī r', + '阿兹特克' => ' a zī tè kè', + '不大离儿' => ' bù dà lí r', + '挨饥抵饿' => ' ái jī dǐ è', + '阿卡迪亚' => ' a kǎ dí yà', + '厄勒布鲁' => ' e lè bù lǔ', + '阿奇里斯' => ' a qí lǐ sī', + '阿里地区' => ' a lǐ dì qū', + '阿布哈兹' => ' a bù hā zī', + '阿布扎比' => ' a bù zā bǐ', + '阿布达比' => ' a bù dá bǐ', + '阿姆哈拉' => ' a mǔ hā lā', + '纳德阿里' => ' nà dé a lǐ', + '阿克苏河' => ' a kè sū hé', + '阿迪达斯' => ' a dí dá sī', + '阿达比尔' => ' a dá bǐ ěr', + '阿时趋俗' => ' ē shí qū sú', + '如饥似渴' => ' rú jī sì kě', + '计日以俟' => ' jì rì yǐ sì', + '巴克科思' => ' bā kè kē sī', + '差不离儿' => ' chà bù lí r', + '呼不给吸' => ' hū bù jǐ xī', + '击其不意' => ' jī qí bù yì', + '鸡皮鹤发' => ' jī pí hè fà', + '大麻哈鱼' => ' dà má hǎ yú', + '耶稣基督' => ' yē sū jī dū', + '叽叽哇哇' => ' jī jī wā wā', + '胳臂箍儿' => ' gē bei gū r', + '自给自足' => ' zì jǐ zì zú', + '格拉斯哥' => ' gé lā sī gē', + '巴耶利巴' => ' bā yē lì bā', + '巴尔的摩' => ' bā ěr dì mó', + '一笔抹摋' => ' yī bǐ mò sà', + '负固不服' => ' fù gù bù fú', + '一大早儿' => ' yī dà zǎo r', + '耶哥尼雅' => ' yē gē ní yǎ', + '欲取姑与' => ' yù qǔ gū yǔ', + '一口气儿' => ' yī kǒu qì r', + '以利亚撒' => ' yǐ lì yà sǎ', + '希腊字母' => ' xī là zì mǔ', + '一语破的' => ' yī yǔ pò dì', + '福斯塔夫' => ' fú sī tǎ fū', + '密密麻麻' => ' mì mì mā mɑ', + '鹤发鸡皮' => ' hè fà jī pí', + '萨格勒布' => ' sà gé lè bù', + '乌尔都语' => ' wū ěr dū yǔ', + '握发吐哺' => ' wò fà tǔ bǔ', + '无以塞责' => ' wú yǐ sè zé', + '乌衣子弟' => ' wū yī zǐ dì', + '呜呜咽咽' => ' wū wū yè yè', + '科纳克里' => ' kē nà kè lǐ', + '不起眼儿' => ' bù qǐ yǎn r', + '傻大个儿' => ' shǎ dà gè r', + '诃佛诋巫' => ' hē fó dǐ wū', + '科迪勒拉' => ' kē dí lè lā', + '余子碌碌' => ' yú zǐ lù lù', + '饿虎之蹊' => ' è hǔ zhī xī', + '父析子荷' => ' fù xī zǐ hé', + '一发破的' => ' yī fā pò dì', + '依撒意亚' => ' yī sā yì yà', + '塔塔儿人' => ' tǎ tǎ r rén', + '不可移易' => ' bù kě yí yì', + '敷衍塞责' => ' fū yǎn sè zé', + '阿育吠陀' => ' a yù fèi tuó', + '三臡八菹' => ' sān ní bā zū', + '喀喇沁旗' => ' kā lā qìn qí', + '阿瓦提县' => ' a wǎ tí xiàn', + '色厉胆薄' => ' sè lì dǎn bó', + '打击乐器' => ' dǎ jī yuè qì', + '克什米尔' => ' kè shí mǐ ěr', + '只字不提' => ' zhī zì bù tí', + '刻木为鹄' => ' kè mù wéi hú', + '喀什地区' => ' kā shí dì qū', + '小媳妇儿' => ' xiǎo xí fu r', + '喀什噶尔' => ' kā shí gá ěr', + '刻木为吏' => ' kè mù wéi lì', + '刻足适屦' => ' kè zú shì jù', + '集体宿舍' => ' jí tǐ sù shè', + '无地自处' => ' wú dì zì chǔ', + '泥古不化' => ' nì gǔ bù huà', + '奥西娜斯' => ' aò xī nuó sī', + '支吾其词' => ' zhī wū qí cí', + '除恶务尽' => ' chú è wù jìn', + '如花似玉' => ' rú huā sì yù', + '胳膊腕子' => ' gē bo wàn zǐ', + '毒泷恶雾' => ' dú lóng è wù', + '阿尔衮琴' => ' a ěr gǔn qín', + '克莱斯勒' => ' kè lái sī lè', + '阿图什市' => ' a tú shí shì', + '刻薄寡思' => ' kè bó guǎ sī', + '鹘入鸦群' => ' hú rù yā qún', + '靡颜腻理' => ' mǐ yán nì lǐ', + '入土为安' => ' rù tú wéi ān', + '磁单极子' => ' cí dān jí zǐ', + '蠹居棋处' => ' dù jū qí chǔ', + '赍志而没' => ' jī zhì ér mò', + '日居月诸' => ' rì jī yuè zh', + '糊涂一时' => ' hú tu yī shí', + '入不敷出' => ' rù bù fū chū', + '阿合奇县' => ' a hé qí xiàn', + '阿尔都塞' => ' a ěr dōu sāi', + '看得过儿' => ' kàn de guò r', + '阿非利加' => ' a fēi lì jiā', + '即心即佛' => ' jí xīn jí fó', + '高足弟子' => ' gāo zú dì zǐ', + '一仆二主' => ' yī pú èr zhǔ', + '目不暇给' => ' mù bù xiá jǐ', + '厚此薄彼' => ' hòu cǐ bó bǐ', + '科尼赛克' => ' kē ní sài kè', + '居礼夫人' => ' jū lǐ fū ren', + '日不暇给' => ' rì bù xiá jǐ', + '画虎刻鹄' => ' huà hǔ kè hú', + '阿克赛钦' => ' a kè sài qīn', + '阿其所好' => ' ē qí suǒ hào', + '螺丝起子' => ' luó sī qǐ zǐ', + '阿勒泰市' => ' a lè tài shì', + '厚积薄发' => ' hòu jī bó fā', + '敌特分子' => ' dí tè fèn zǐ', + '握发吐飧' => ' wò fà tǔ sūn', + '吁咈都俞' => ' yù fú dōu yú', + '积极分子' => ' jī jí fèn zǐ', + '稀里哗啦' => ' xī lǐ huā lā', + '诘屈聱牙' => ' jié qū áo yá', + '予取予夺' => ' yú qǔ yú duó', + '予取予求' => ' yú qǔ yú qiú', + '予取予携' => ' yú qǔ yú xié', + '厄勒海峡' => ' e lè hǎi xiá', + '泰西大儒' => ' tài xī dà rú', + '膏腴子弟' => ' gāo yú zǐ dì', + '包袱底儿' => ' bāo fú dǐ ér', + '梅妻鹤子' => ' méi qī hè zǐ', + '呼卢喝雉' => ' hū lú hè zhì', + '我黼子佩' => ' wǒ fǔ zǐ pèi', + '我负子戴' => ' wǒ fù zǐ dài', + '不足为虑' => ' bù zú wéi lǜ', + '高歌一曲' => ' gāo gē yī qǔ', + '虚与委蛇' => ' xū yǔ wēi yí', + '胡子拉碴' => ' hú zǐ lā chā', + '毛发丝粟' => ' máo fà sī sù', + '秘鲁苦蘵' => ' bì lǔ kǔ zhí', + '第二个人' => ' dì èr ge rén', + '热毛子马' => ' rè máo zǐ mǎ', + '懒得搭理' => ' lǎn de dā lǐ', + '群雌粥粥' => ' qún cí yù yù', + '扎格罗斯' => ' zā gé luó sī', + '人莫予毒' => ' rén mò yú dú', + '故家子弟' => ' gù jiā zǐ dì', + '居里夫人' => ' jū lǐ fū ren', + '模糊逻辑' => ' mó hu luó ji', + '遭遇不偶' => ' zāo yù bù ǒu', + '塞拉耶佛' => ' sè lā yē fó', + '结发夫妻' => ' jié fà fū qī', + '曲突移薪' => ' qǔ tū yí xīn', + '叽里呱啦' => ' jī lǐ guā lā', + '以苦为乐' => ' yǐ kǔ wéi lè', + '铆足劲儿' => ' mǎo zú jìn r', + '以蠡测海' => ' yǐ lǐ cè hǎi', + '失而复得' => ' shī ér fù de', + '绕弯子儿' => ' rào wān zǐ r', + '以鹿为马' => ' yǐ lù wéi mǎ', + '时移俗易' => ' shí yí sú yì', + '纨绔子弟' => ' wán kù zǐ dì', + '核子医学' => ' hé zǐ yī xué', + '母以子贵' => ' mǔ yǐ zǐ guì', + '马拉喀什' => ' mǎ lā kā shí', + '扞格不入' => ' hàn gé bù rù', + '绿林起义' => ' lù lín qǐ yì', + '碌碌无为' => ' lù lù wú wéi', + '狗玩儿的' => ' gǒu wán r de', + '不可分割' => ' bù kě fēn gē', + '勒维纳斯' => ' lè wéi nà sī', + '博物君子' => ' bó wù jūn zǐ', + '撒马尔罕' => ' sǎ mǎ ěr hǎn', + '过河卒子' => ' guò hé zú zǐ', + '哇哩哇啦' => ' wā lǐ wā lā', + '吐哺握发' => ' tǔ bǔ wò fà', + '除恶务本' => ' chú è wù běn', + '曲不离口' => ' qǔ bù lí kǒu', + '卖妻鬻子' => ' mài qī yù zǐ', + '不计其数' => ' bù jì qí shù', + '参差不齐' => ' cēn cī bù qí', + '勒哈费尔' => ' lè hā fèi ěr', + '异议分子' => ' yì yì fèn zǐ', + '妻离子散' => ' qī lí zǐ sàn', + '不拔一毛' => ' bù bá yì máo', + '去本趋末' => ' qù běn qū mò', + '吱哩哇啦' => ' zhī lī wā lā', + '纨裤子弟' => ' wán kù zǐ dì', + '亚麻子油' => ' yà má zǐ yóu', + '皈依佛法' => ' guī yī fó fǎ', + '积露为波' => ' jī lù wéi bō', + '曲学阿世' => ' qǔ xué ā shì', + '撒马尔干' => ' sǎ mǎ ěr gàn', + '依阿取容' => ' yī ē qǔ róng', + '压压脚儿' => ' yā ya jiǎo r', + '爱民如子' => ' ài mín rú zǐ', + '徒子徒孙' => ' tú zǐ tú sūn', + '兔起鹘落' => ' tù qǐ hú luò', + '以斯帖记' => ' yǐ sī tiě jì', + '误人子弟' => ' wù rén zǐ dì', + '格子花呢' => ' gé zi huā ní', + '姿态婀娜' => ' zī tài ē nuó', + '格洛斯特' => ' gé luò sī tè', + '格洛纳斯' => ' gé luò nà sī', + '慕古薄今' => ' mù gǔ bó jīn', + '铁哥们儿' => ' tiě gē men r', + '拭目以俟' => ' shì mù yǐ sì', + '不足为奇' => ' bù zú wéi qí', + '洗发水儿' => ' xǐ fà shuǐ r', + '为法自弊' => ' wéi fǎ zì bì', + '法尔卡什' => ' fǎ ěr kǎ shí', + '喜不自禁' => ' xǐ bù zì jīn', + '阿尔加维' => ' a ěr jiā wéi', + '擘肌分理' => ' bò jī fēn lǐ', + '疾不可为' => ' jí bù kě wéi', + '易子而食' => ' yì zǐ ér shí', + '以耳为目' => ' yǐ ěr wéi mù', + '塞浦路斯' => ' sài pǔ lù sī', + '拿印把儿' => ' ná yìn bà er', + '服务态度' => ' fú wù tài du', + '狐狸尾巴' => ' hú li wěi ba', + '易卜拉辛' => ' yì bǔ lā xīn', + '罗马尼亚' => ' luō mǎ ní yà', + '木骨都束' => ' mù gǔ dū shù', + '一呵而就' => ' yī hē ér jiù', + '细细地流' => ' xì xì de líu', + '不对劲儿' => ' bù duì jìn r', + '闭门塞户' => ' bì kǒu sè hù', + '词不逮意' => ' cí bù dài yì', + '词不逮理' => ' cí bù dài lǐ', + '干戈四起' => ' gān gē sì qǐ', + '至死靡它' => ' zhì sǐ mǐ tā', + '不对碴儿' => ' bù duì chá r', + '认死扣儿' => ' rèn sǐ kòu r', + '唏哩哗啦' => ' xī lī huā lā', + '六枝特区' => ' lù zhī tè qū', + '默而识之' => ' mò ér zhì zhī', + '批亢抵巇' => ' pī gāng dǐ xī', + '著作权法' => ' zhù zuò quán fǎ', + '引以为憾' => ' yǐn yǐ wéi hàn', + '分子杂交' => ' fēn zǐ zá jiāo', + '含情脉脉' => ' hán qíng mò mò', + '氧乙炔炬' => ' yǎng yǐ quē jù', + '偏差距离' => ' piān chā jù lí', + '书不尽言' => ' shū bù jìn yán', + '塞韦里诺' => ' sài wéi lǐ nuò', + '一呼百应' => ' yī hū bǎi yìng', + '弹射座椅' => ' tán shè zuò yǐ', + '大动干戈' => ' dà dòng gān gē', + '夙兴夜寐' => ' sù xīng yè mèi', + '一吐为快' => ' yī tǔ wéi kuài', + '孤家寡人' => ' gū jiā guǎ rén', + '有好奇心' => ' yǒu hào qí xīn', + '有子存焉' => ' yǒu zǐ cún yān', + '有朝一日' => ' yǒu zhāo yī rì', + '全军覆没' => ' quán jūn fù mò', + '朝露溘至' => ' zhāo lù kè zhì', + '几乎完全' => ' jī hū wán quán', + '含糊不清' => ' hán hu bù qīng', + '有头无尾' => ' yǒu tóu wú wěi', + '跑堂儿的' => ' pǎo táng r de', + '信而好古' => ' xìn ér hào gǔ', + '恫疑虚猲' => ' dòng yí xū gé', + '恫疑虚喝' => ' dòng yí xū hè', + '干云蔽日' => ' gān yún bì rì', + '公子哥儿' => ' gōng zǐ gē ér', + '处理办法' => ' chǔ lǐ bàn fǎ', + '嗓子眼儿' => ' sǎng zi yǎn r', + '乌踆兔走' => ' wū cún tù zǒu', + '离本徼末' => ' lí běn yāo mò', + '数理逻辑' => ' shù lǐ luó ji', + '出处语默' => ' chū chǔ yǔ mò', + '刚直不阿' => ' gāng zhí bù ē', + '身体发肤' => ' shēn tǐ fà fū', + '亚塞拜然' => ' yà sè bài rán', + '丑类恶物' => ' chǒu lèi è wù', + '节骨眼儿' => ' jiē gu yǎn er', + '五尺竖子' => ' wǔ chǐ shù zǐ', + '瞰瑕伺隙' => ' kàn xiá sì xì', + '一劳永逸' => ' yī láo yǒng yì', + '张掖地区' => ' zhāng yè dì qū', + '言不尽意' => ' yán bù jìn yì', + '孙子兵法' => ' sūn zǐ bīng fǎ', + '彼唱此和' => ' bǐ chàng cǐ hè', + '彬彬君子' => ' bīn bīn jūn zǐ', + '一小阵儿' => ' yī xiǎo zhèn r', + '值得品味' => ' zhí de pǐn wèi', + '一小部分' => ' yī xiǎo bù fèn', + '广安地区' => ' guǎng ān dì qū', + '沉不住气' => ' chén bú zhù qì', + '沉得住气' => ' chén de zhù qì', + '多劳多得' => ' duō láo duō de', + '往心里去' => ' wǎng xīn li qù', + '沐猴而冠' => ' mù hóu ér guàn', + '木管乐器' => ' mù guǎn yuè qì', + '会计制度' => ' kuài jì zhì dù', + '值得信赖' => ' zhí de xìn lài', + '分而治之' => ' fēn ér zhì zhī', + '柔情脉脉' => ' róu qíng mò mò', + '人尽其才' => ' rén jìn qí cái', + '不为酒困' => ' bù wéi jǐu kùn', + '凸面部分' => ' tū miàn bù fèn', + '借方差额' => ' jiè fāng chā é', + '孑孑为义' => ' jié jié wéi yì', + '和记黄埔' => ' hé jì huáng pǔ', + '挑三窝四' => ' tiǎo sān wō sì', + '咬舌自尽' => ' yǎo shé zì jìn', + '一干二净' => ' yī gān èr jìng', + '孔子家语' => ' kǒng zǐ jiā yǔ', + '克什克腾' => ' kè shí kè téng', + '压轴好戏' => ' yā zhòu hǎo xì', + '朝三暮四' => ' zhāo sān mù sì', + '没齿不忘' => ' mò chǐ bù wàng', + '安步当车' => ' ān bù dàng chē', + '厦门大学' => ' xià mén dà xué', + '一唱一和' => ' yī chàng yī hè', + '安分守己' => ' ān fèn shǒu jǐ', + '倒背手儿' => ' dào bèi shǒu r', + '曾外祖母' => ' zēng wài zǔ mǔ', + '曾外祖父' => ' zēng wài zǔ fù', + '水磨沟区' => ' shuǐ mò gōu qū', + '多那太罗' => ' duō nǎ tài luó', + '往泥里踩' => ' wǎng nì lǐ cǎi', + '神不附体' => ' shén bù fù tǐ', + '出奇划策' => ' chū qí huá cè', + '新式拚法' => ' xīn shì pīn fǎ', + '德薄才疏' => ' dé bó cái shū', + '新斯科舍' => ' xīn sī kē shè', + '动嘴皮儿' => ' dòng zuǐ pí r', + '精子密度' => ' jīng zǐ mì dù', + '应付自如' => ' yìng fù zì rú', + '右翼分子' => ' yòu yì fēn zǐ', + '扎欧扎翁' => ' zā ōu zā wēng', + '扎马鲁丁' => ' zā mǎ lǔ dīng', + '感激不尽' => ' gǎn jī bù jìn', + '爱丽思泉' => ' aì lí sī quán', + '糖醋里脊' => ' táng cù lǐ jǐ', + '丢卒保车' => ' diū zú bǎo jū', + '结结巴巴' => ' jiē jiē bā bā', + '日积月累' => ' rì jī yuè lěi', + '干戈载戢' => ' gàn gē zǎi jí', + '绝大部分' => ' jué dà bù fen', + '络腮胡子' => ' luò sāi hú zǐ', + '依样葫芦' => ' yī yàng hú lu', + '视民如子' => ' shì mín rú zǐ', + '落魄不偶' => ' luo tuo bu ou', + '落拓不羁' => ' luò tuò bù jī', + '推枯折腐' => ' tuī kū shé fǔ', + '实逼处此' => ' shí bī chǔ cǐ', + '没金饮羽' => ' mò jīn yǐn yǔ', + '数以万计' => ' shǔ yǐ wàn jì', + '引以为傲' => ' yǐn yǐ wéi ào', + '纶音佛语' => ' lún yīn fó yǔ', + '东抹西涂' => ' dōng mò xī tú', + '纳什维尔' => ' nà shí wéi ěr', + '弹拨乐器' => ' tán bō yuè qì', + '纽几内亚' => ' nǐu jī nèi yà', + '人给家足' => ' rén jǐ jiā zú', + '逻辑思维' => ' luó ji sī wéi', + '心里踏实' => ' xīn li tā shi', + '五侯蜡烛' => ' wǔ hòu là zhú', + '纳粹分子' => ' nà cuì fèn zǐ', + '素食主义' => ' sù shí zhǔ yì', + '人才济济' => ' rén cái jǐ jǐ', + '应付裕如' => ' yìng fù yù rú', + '处心积虑' => ' chǔ xīn jī lǜ', + '引喻失义' => ' yǐn yù shī yì', + '锡林郭勒' => ' xī lín guō lè', + '以意为之' => ' yǐ yì wéi zhī', + '梨俱吠陀' => ' lí jū fèi tuó', + '分析处理' => ' fēn xī chǔ lǐ', + '等一下儿' => ' děng yī xià r', + '为民父母' => ' wéi mín fù mǔ', + '恶不去善' => ' wù bù qù shàn', + '膏车秣马' => ' gào chē mò mǎ', + '奥切诺斯' => ' aò qiē nuò sī', + '高义薄云' => ' gāo yì bó yún', + '个别差异' => ' gè bié chā yì', + '二道贩子' => ' èr dào fàn zǐ', + '二十八宿' => ' èr shí bā xiù', + '梨园子弟' => ' lí yuán zǐ dì', + '唐突西子' => ' táng tū xī zǐ', + '悬崖勒马' => ' xuán yá lè mǎ', + '泪眼模糊' => ' lèi yǎn mó hu', + '森海塞尔' => ' sēn hǎi sè ěr', + '有机分子' => ' yǒu jī fēn zǐ', + '蜜月假期' => ' mì yuè jià qī', + '累土聚沙' => ' lěi tǔ jù shā', + '奥维耶多' => ' aò wéi yē duō', + '等一会儿' => ' děng yī huì r', + '等离子体' => ' děng lí zǐ tǐ', + '扎马剌丁' => ' zā mǎ lá dīng', + '无间可伺' => ' wú jiān kě sì', + '无理要求' => ' wú lǐ yāo qiú', + '细胞因子' => ' xì bāo yīn zǐ', + '细磨刀石' => ' xì mò dāo shí', + '因敌为资' => ' yīn dí wéi zī', + '恶居下流' => ' wù jū xià liú', + '犁牛之子' => ' lí niú zhī zǐ', + '无尽无休' => ' wú jìn wú xiū', + '会计科目' => ' kuài jì kē mù', + '无后为大' => ' wú hòu wéi dà', + '筋疲力尽' => ' jīn pí lì jìn', + '具体地说' => ' jù tǐ de shuō', + '五侯七贵' => ' wǔ hòu qī guì', + '力尽筋疲' => ' lì jìn jīn pí', + '淫词艳曲' => ' yín cí yàn qǔ', + '曲高和寡' => ' qǔ gāo hè guǎ', + '五斗米道' => ' wǔ dǒu mǐ dào', + '数据处理' => ' shù jù chǔ lǐ', + '高干子弟' => ' gāo gàn zǐ dì', + '嘉柏隆里' => ' jiā bó lóng lǐ', + '参差错落' => ' cēn cī cuò luò', + '委肉虎蹊' => ' wěi ròu hǔ xī', + '各有所好' => ' gè yǒu suǒ hào', + '松巴哇岛' => ' sōng bā wā dǎo', + '一盘散沙' => ' yī pán sǎn shā', + '一目了然' => ' yī mù liǎo rán', + '一目十行' => ' yī mù shí háng', + '一网打尽' => ' yī wǎng dǎ jìn', + '忍俊不禁' => ' rěn jùn bù jīn', + '国际关系' => ' guó jì guān xì', + '拨弦乐器' => ' bō xián yuè qì', + '佛口蛇心' => ' fó kǒu shé xīn', + '俄勒冈州' => ' e lè gāng zhōu', + '悲歌当哭' => ' bēi gē dàng kū', + '情不自禁' => ' qíng bù zì jīn', + '嗳腐吞酸' => ' ài fǔ tūn suān', + '哩溜歪斜' => ' li liū wāi xié', + '伽马射线' => ' gā mǎ shè xiàn', + '不可估量' => ' bù kě gū liang', + '失败主义' => ' shī bài zhǔ yì', + '伸缩喇叭' => ' shēn suō lǎ ba', + '子弹火车' => ' zǐ dàn huǒ chē', + '带电粒子' => ' dài diàn lì zǐ', + '可数名词' => ' kě shǔ míng cí', + '倒戈卸甲' => ' dǎo gē xiè jiǎ', + '剃发留辫' => ' tì fà líu biàn', + '拉开架势' => ' lā kāi jià shi', + '天雨路滑' => ' tiān yù lù huá', + '前途未卜' => ' qián tú wèi bǔ', + '子宫肌瘤' => ' zǐ gōng jī liú', + '殒身不恤' => ' yǔn shēn bú xù', + '侯门似海' => ' hóu mén sì hǎi', + '列别杰夫' => ' liè biè jié fū', + '气鸣乐器' => ' qì míng yuè qì', + '信号处理' => ' xìn hào chǔ lǐ', + '杜松子酒' => ' dù sōng zǐ jiǔ', + '大有作为' => ' dà yǒu zuò wéi', + '一气呵成' => ' yī qì hē chéng', + '室町幕府' => ' shì tǐng mù fǔ', + '心肌梗塞' => ' xīn jī gěng sè', + '心里有数' => ' xīn li yǒu shù', + '曲麻莱县' => ' qǔ má lái xiàn', + '列宁格勒' => ' liè níng gé lè', + '嗳气吞酸' => ' ài qì tūn suān', + '意犹未尽' => ' yì yóu wèi jìn', + '急公好义' => ' jí gōng hào yì', + '切理会心' => ' qiē lǐ huì xīn', + '啰里啰嗦' => ' luō li luō suo', + '罗曼带克' => ' luō màn dài kè', + '佛朗机炮' => ' fó lǎng jī pào', + '柔佛海峡' => ' róu fó hǎi xiá', + '佛兰芒语' => ' fó lán máng yǔ', + '互为因果' => ' hù wéi yīn guò', + '一一对应' => ' yī yī duì yìng', + '贫嘴薄舌' => ' pín zuǐ bó shé', + '大煞风趣' => ' dà shà fēng qù', + '四大名著' => ' sì dà míng zhù', + '一成不易' => ' yī chéng bù yì', + '面似靴皮' => ' miàn sì xuē pí', + '大肆铺张' => ' dà sì pū zhāng', + '改曲易调' => ' gǎi qǔ yì diào', + '义薄云天' => ' yì bó yún tiān', + '改口沓舌' => ' gǎi kǒu tà shé', + '改恶为善' => ' gǎi è wéi shàn', + '抱法处势' => ' bào fǎ chǔ shì', + '右派分子' => ' yòu pài fèn zǐ', + '恣意妄为' => ' zì yì wàng wéi', + '步罡踏斗' => ' bù gāng tà dǒu', + '不干不净' => ' bù gān bù jìng', + '昌都地区' => ' chāng dū dì qū', + '步步为营' => ' bù bù wéi yíng', + '助人为乐' => ' zhù rén wéi lè', + '步斗踏罡' => ' bù dǒu tà gāng', + '核战斗部' => ' hé zhàn dǒu bù', + '任人宰割' => ' rèn rén zǎi gē', + '夷为平地' => ' yí wéi píng dì', + '暴虎冯河' => ' bào hǔ píng hé', + '托勒密王' => ' tuō lè mì wáng', + '死海古卷' => ' sǐ hǎi gǔ juàn', + '太仆寺卿' => ' tài pú sì qīng', + '各奔东西' => ' gè bèn dōng xī', + '恐怖分子' => ' kǒng bù fèn zi', + '恐怖片儿' => ' kǒng bù piān r', + '四海为家' => ' sì hǎi wéi jiā', + '四方台区' => ' sì fāng tái qū', + '是非曲直' => ' shì fēi qǔ zhí', + '太子太保' => ' tài zǐ tài bǎo', + '佳人才子' => ' jiā rén cái zǐ', + '到此为止' => ' dào cǐ wéi zhǐ', + '封妻荫子' => ' fēng qī yìn zǐ', + '朝不保夕' => ' zhāo bù bǎo xī', + '爱丽舍宫' => ' ài lì shè gōng', + '不怀好意' => ' bù huái hào yì', + '慈悲为本' => ' cí bēi wéi běn', + '反客为主' => ' fǎn kè wéi zhǔ', + '人际关系' => ' rén jì guān xì', + '不是东西' => ' bù shì dōng xi', + '嘎嘎小姐' => ' gā gā xiǎo jie', + '反叛分子' => ' fǎn pàn fèn zǐ', + '勉力而为' => ' miǎn lì ér wéi', + '仁人君子' => ' rén rén jūn zǐ', + '以人为本' => ' yǐ rén wéi běn', + '棋高一着' => ' qí gāo yī zhāo', + '找台阶儿' => ' zhǎo tái jiē r', + '印度音乐' => ' yìn dù yīn yuè', + '南箕北斗' => ' nán jī běi dǒu', + '妄自菲薄' => ' wàng zì fěi bó', + '打家劫舍' => ' dǎ jiā jié shè', + '乳臭未干' => ' rǔ xiù wèi gān', + '不为已甚' => ' bù wéi yǐ shèn', + '仁至义尽' => ' rén zhì yì jìn', + '小苏打粉' => ' xiǎo sū dá fěn', + '文书处理' => ' wén shū chǔ lǐ', + '动弹不得' => ' dòng tan bù dé', + '嘉兴地区' => ' jiā xīng dì qū', + '投其所好' => ' tóu qí suǒ hào', + '斗酒只鸡' => ' dǒu jiǔ zhī jī', + '五行八作' => ' wǔ háng bā zuò', + '技术知识' => ' jì shù zhī shi', + '化敌为友' => ' huà dí wéi yǒu', + '文艺复兴' => ' wén yì fù xīng', + '斜愣眼儿' => ' xié leng yǎn r', + '哲人其萎' => ' zhé rén qí wěi', + '化为乌有' => ' huà wéi wū yǒu', + '人尽其材' => ' rén jìn qí cái', + '不为人知' => ' bù wéi rén zhī', + '令狐德棻' => ' líng hú dé fēn', + '代数拓扑' => ' dài shù tuò pū', + '受冻挨饿' => ' shòu dòng ái è', + '委靡不振' => ' wěi mǐ bù zhèn', + '委内瑞拉' => ' wěi nèi ruì lā', + '危如朝露' => ' wēi rú zhāo lù', + '小菜碟儿' => ' xiǎo cài dié r', + '拓扑结构' => ' tuò pū jié gòu', + '一语中的' => ' yī yǔ zhōng dì', + '才子佳人' => ' cái zǐ jiā rén', + '才高八斗' => ' cái gāo bā dǒu', + '干脆利落' => ' gān cuì lì luò', + '堆案盈几' => ' duī àn yíng jī', + '巨海扇蛤' => ' jù hǎi shàn gé', + '核电荷数' => ' hé diàn hè shù', + '一言难尽' => ' yī yán nán jìn', + '别具只眼' => ' bié jù zhī yǎn', + '林荫大道' => ' lín yìn dà dào', + '手板葫芦' => ' shǒu bǎn hú lu', + '搞花样儿' => ' gǎo huā yàng r', + '母音调和' => ' mǔ yīn tiáo hé', + '枯草杆菌' => ' kū cǎo gǎn jūn', + '怎么得了' => ' zěn me dé liǎo', + '巴塞隆纳' => ' bā sài lóng nà', + '希腊神话' => ' xī là shén huà', + '供大于求' => ' gòng dà yú qiú', + '利他行为' => ' lì tā xíng wéi', + '卑鄙龌龊' => ' bēi bǐ wò chuò', + '极端分子' => ' jí duān fèn zǐ', + '小时候儿' => ' xiǎo shí hou r', + '数不过来' => ' shǔ bù guò lái', + '打躬作揖' => ' dǎ gōng zuō yī', + '乙种粒子' => ' yǐ zhǒng lì zǐ', + '启应祈祷' => ' qǐ yìng qí dǎo', + '好自为之' => ' hào zì wéi zhī', + '棒子面儿' => ' bàng zi miàn r', + '扼襟控咽' => ' è jīn kòng yān', + '尺寸过大' => ' chǐ cun guò dà', + '千钧一发' => ' qiān jūn yī fà', + '戴高帽子' => ' dài gāo mào zǐ', + '败子回头' => ' bài zǐ huí tóu', + '原子序数' => ' yuán zǐ xù shù', + '并不在乎' => ' bìng bù zài hu', + '极深研几' => ' jí shēn yán jī', + '极为庞大' => ' jí wéi páng dà', + '好大喜功' => ' hào dà xǐ gōng', + '丫头片子' => ' yā tou piān zi', + '手扳葫芦' => ' shǒu bān hú lu', + '横竖劲儿' => ' héng shù jìn r', + '分离分子' => ' fēn lí fèn zǐ', + '家给民足' => ' jiā jǐ mín zú', + '一般贸易' => ' yī bān mào yì', + '网路特务' => ' wǎng lù tè wu', + '以邻为壑' => ' yǐ lín wéi hè', + '干巴利落' => ' gān bā lì luò', + '昆都仑区' => ' kūn dū lún qū', + '羿射九日' => ' yì shè jiǔ rì', + '干巴利脆' => ' gān bā lì cuì', + '多哈回合' => ' duō hā huí hé', + '无为自化' => ' wú wéi zì huà', + '路易十六' => ' lù yì shí liù', + '以为后图' => ' yǐ wéi hòu tú', + '鲁难未已' => ' lǔ nàn wèi yǐ', + '无为而治' => ' wú wéi ér zhì', + '绿林豪客' => ' lù lín háo kè', + '詈夷为跖' => ' lì yí wéi zhí', + '偶一为之' => ' ǒu yī wéi zhī', + '经济体系' => ' jīng jì tǐ xì', + '大大咧咧' => ' dà dà liē liē', + '地区差价' => ' dì qū chā jià', + '格物致知' => ' gé wù zhì zhī', + '塞拉利昂' => ' sài lā lì áng', + '物稀为贵' => ' wù xī wéi guì', + '夹起尾巴' => ' jiā qǐ wěi ba', + '佛山地区' => ' fó shān dì qū', + '耶稣会士' => ' yē sū huì shì', + '束蒲为脯' => ' shù pú wéi pú', + '大而无当' => ' dà ér wú dàng', + '附肤落毛' => ' fù fū luò máo', + '耳鼻咽喉' => ' ěr bí yān hóu', + '服服帖帖' => ' fú fu tiē tiē', + '打打闹闹' => ' dá dǎ nào nào', + '符号逻辑' => ' fú hào luó ji', + '昭披耶河' => ' zhāo pī yē hé', + '以牙还牙' => ' yǐ yá huán yá', + '值得注意' => ' zhí de zhù yì', + '符合要求' => ' fú hé yāo qiú', + '耶律大石' => ' yē lù: dà shí', + '以己度人' => ' yǐ jǐ duó rén', + '罗切斯特' => ' luó qiē sī tè', + '移天易日' => ' yí tiān yì rì', + '易俗移风' => ' yì sú yí fēng', + '以书为御' => ' yǐ shū wéi yù', + '一夕一朝' => ' yī xī yī zhāo', + '砥砺琢磨' => ' dǐ lì zhuó mó', + '耶路撒冷' => ' yē lù sā lěng', + '须发皆白' => ' xū fà jiē bái', + '差不多的' => ' chà bu duō de', + '差一点儿' => ' chà yī diǎn r', + '一切万物' => ' yī qiē wàn wù', + '视为儿戏' => ' shì wéi ér xì', + '丝毫不差' => ' sī háo bù chā', + '恶迹昭著' => ' è jì zhāo zhù', + '凯撒肋雅' => ' kǎi sā lèi yǎ', + '巴马干酪' => ' bā mǎ gān lào', + '死亡无日' => ' sǐ wáng wú rì', + '岂弟君子' => ' kǎi tì jūn zǐ', + '与时俱进' => ' yǔ shí jū jìn', + '伺瑕导隙' => ' sì xiá dǎo xì', + '法家拂士' => ' fǎ jiā bì shì', + '羞与为伍' => ' xiū yǔ wéi wǔ', + '倒持太阿' => ' dǎo chí tài ā', + '羞人答答' => ' xiū rén dā dā', + '布干维尔' => ' bù gān wéi ěr', + '布隆伯格' => ' bù lōng bó gé', + '一谦四益' => ' yī qiān sì yì', + '绿林大盗' => ' lù lín dà dào', + '藉资挹注' => ' jiè zī yì zhù', + '吾自有处' => ' wu zi you chu', + '石头子儿' => ' shí tou zǐ er', + '一脚不移' => ' yī jiǎo bù yí', + '骂骂咧咧' => ' mà mà liē liē', + '意念移物' => ' yì niàn yí wù', + '置之死地' => ' zhì zhī sǐ dì', + '加利肋亚' => ' jiā lì lèi yà', + '置之不理' => ' zhì zhī bù lǐ', + '多子多福' => ' duō zǐ duō fú', + '一劳久逸' => ' yī láo jiǔ yì', + '一目五行' => ' yī mù wǔ háng', + '恶紫夺朱' => ' wù zǐ duó zhū', + '加勒比海' => ' jiā lè bǐ hǎi', + '五子登科' => ' wǔ zǐ dēng kē', + '实与有力' => ' shí yù yǒu lì', + '加德满都' => ' jiā dé mǎn dū', + '萨摩耶犬' => ' sà mó yē quǎn', + '加里肋亚' => ' jiā lǐ lèi yà', + '时移世易' => ' shí yí shì yì', + '临难不惧' => ' lín nàn bù jǔ', + '耶酥会士' => ' yē sū huì shì', + '羞羞答答' => ' xiū xiū dā dā', + '爱莫之助' => ' ài mò zhī zhù', + '不对茬儿' => ' bú duì chá ér', + '不用客气' => ' bù yòng kè qi', + '投机倒把' => ' tóu jī dǎo bǎ', + '鹤处鸡群' => ' hè chǔ jī qún', + '毕毕剥剥' => ' bì bì bāo bāo', + '朱颜绿发' => ' zhū yán lǜ fà', + '拖拖沓沓' => ' tuō tuō tà tà', + '财殚力痡' => ' cái dān lì pū', + '吉电子伏' => ' jí diàn zǐ fú', + '曲曲折折' => ' qū qū zhé shé', + '刿鉥心腑' => ' guì xù xīn fǔ', + '画地为狱' => ' huà dì wéi yù', + '朱颜鹤发' => ' zhū yán hè fà', + '千里一曲' => ' qiān lǐ yī qǔ', + '才疏德薄' => ' cái shū dé bó', + '取之不尽' => ' qǔ zhī bù jìn', + '狐藉虎威' => ' hú jiè hǔ wēi', + '否去泰来' => ' pǐ qù tài lái', + '只鸡絮酒' => ' zhī jī xù jiǔ', + '蒿子秆儿' => ' hāo zǐ gǎn ér', + '据为己有' => ' jù wéi jǐ yǒu', + '泥古拘方' => ' nì gǔ jū fāng', + '世界屋脊' => ' shì jiè wū jǐ', + '不足齿数' => ' bù zú chǐ shǔ', + '不足为道' => ' bù zú wéi dào', + '家给人足' => ' jiā jǐ rén zú', + '掎挈伺诈' => ' jǐ qiè sì zhà', + '鸡毛掸子' => ' jī máo dǎn zǐ', + '鹤发松姿' => ' hè fà sōng zī', + '一年四季' => ' yì nián sì jì', + '曲意迎合' => ' qǔ yì yíng hé', + '一哄而起' => ' yī hòng ér qǐ', + '不置可否' => ' bù zhì kě fǒu', + '呲牙咧嘴' => ' zī yá liě zuǐ', + '被褐怀玉' => ' pī hè huái yù', + '泥古非今' => ' nì gǔ fēi jīn', + '洛克菲勒' => ' luò kè fēi lè', + '男子气概' => ' nán zǐ qì gài', + '不当得利' => ' bù dàng de lì', + '止戈为武' => ' zhǐ gē wéi wǔ', + '无以为报' => ' wú yǐ wéi bào', + '纪律处分' => ' jì lǜ chǔ fèn', + '聊以塞责' => ' liáo yǐ sè zé', + '覆亡无日' => ' fù wáng wú rì', + '服务行业' => ' fú wù háng yè', + '移风易俗' => ' yí fēng yì sú', + '梨园弟子' => ' lí yuán dì zǐ', + '一佛出世' => ' yī fó chū shì', + '似是而非' => ' sì shì ér fēi', + '功不可没' => ' gōng bù kě mò', + '一毫不差' => ' yī háo bù chā', + '金发碧眼' => ' jīn fà bì yǎn', + '攒眉蹙额' => ' cuán mei cù é', + '嗳气腐臭' => ' ài qì fǔ chòu', + '书不尽意' => ' shū bù jìn yì', + '恶迹昭着' => ' è jì zhāo zhe', + '恰如其分' => ' qià rú qí fèn', + '大有可为' => ' dà yǒu kě wéi', + '投河自尽' => ' tóu hé zì jìn', + '大气磅礴' => ' dà qì páng bó', + '大璞不完' => ' tài bú bù wán', + '大拇指头' => ' dà mǔ zhǐ tou', + '父为子隐' => ' fù wéi zǐ yǐn', + '一定不易' => ' yī dìng bù yì', + '哈巴河县' => ' hā bā hé xiàn', + '失去意识' => ' shī qù yì shí', + '卑鄙无耻' => ' bēi bǐ wú chǐ', + '无所不为' => ' wú suǒ bù wéi', + '畸流洽客' => ' jī liú qià kè', + '孺子可教' => ' rú zǐ kě jiào', + '伺瑕抵蠙' => ' sì xiá dǐ pín', + '集腋为裘' => ' jí yè wéi qiú', + '嗳气酸腐' => ' ài qì suān fǔ', + '福孙荫子' => ' fú sūn yìn zǐ', + '低音提琴' => ' dī yīn tí qín', + '头足异处' => ' tóu zú yì chǔ', + '俯拾地芥' => ' fǔ shí dì jiè', + '解衣衣人' => ' jiè yī yī rén', + '头没杯案' => ' tóu mò bēi àn', + '投袂荷戈' => ' tóu mèi hè gē', + '万柏林区' => ' wàn bó lín qū', + '浮名薄利' => ' fú míng bó lì', + '负气斗狠' => ' fù qì dǒu hěn', + '喷薄欲出' => ' pēn bó yù chū', + '似醉如痴' => ' sì zuì rú chī', + '别太客气' => ' bié tài kè qi', + '喀拉汗国' => ' kā lā hán guó', + '笃学好古' => ' dǔ xué hào gǔ', + '苏州码子' => ' sū zhōu mǎ zǐ', + '闭目塞听' => ' bì mù sè tīng', + '闭门塞窦' => ' bì kǒu sè dòu', + '歙漆阿胶' => ' shè qī ē jiāo', + '文似其人' => ' wén sì qí rén', + '桃蹊柳曲' => ' táo qī liǔ qǔ', + '朝露暮霭' => ' zhāo lù mù ǎi', + '没世无闻' => ' mò shì wú wén', + '业余教育' => ' yè yú jiào yù', + '外孙女儿' => ' wài sūn nǔ: r', + '门单户薄' => ' mén dān hù bó', + '斗绝一隅' => ' dǒu jué yī yú', + '娱妻弄子' => ' yú qī nòng zǐ', + '数一数二' => ' shǔ yī shǔ èr', + '御史大夫' => ' yù shǐ dài fū', + '西格蒙德' => ' xī gé mēng dé', + '吁天呼地' => ' yù tiān hū dì', + '优游自得' => ' yōu yóu zì dé', + '渔阳鞞鼓' => ' yǔ yáng pí gǔ', + '靡靡之乐' => ' mǐ mǐ zhī yuè', + '屈指可数' => ' qū zhǐ kě shǔ', + '读书君子' => ' dú shū jūn zǐ', + '居民点儿' => ' jū mín diǎn r', + '毓子孕孙' => ' yù zǐ yùn sūn', + '阿克塞县' => ' a kè sài xiàn', + '阿什拉维' => ' a shén lā wéi', + '帷薄不修' => ' wéi bó bù xiū', + '谓予不信' => ' wèi yú bù xìn', + '郁郁累累' => ' yù yù lěi lěi', + '手拉葫芦' => ' shǒu lā hú lu', + '卑辞厚币' => ' bēi cí hòu bì', + '尼勒克县' => ' ní lè kè xiàn', + '阿克陶县' => ' a kè táo xiàn', + '尺布斗粟' => ' chǐ bù dǒu sù', + '为恶不悛' => ' wéi è bù quān', + '斗米尺布' => ' dǒu mǐ chǐ bù', + '血肉模糊' => ' xuè ròu mó hu', + '神乎其技' => ' shén hū qí jì', + '未为不可' => ' wèi wéi bù kě', + '阿图什县' => ' a tú shí xiàn', + '孝子爱日' => ' xiào zǐ ài rì', + '大吃苦头' => ' dà chī kǔ tou', + '杜默为诗' => ' dù mò wéi shī', + '靡衣偷食' => ' mǐ yī tōu shí', + '衣单食薄' => ' yī dān shí bó', + '阿旺曲培' => ' a wàng qū péi', + '克仑特罗' => ' kè lún tè luō', + '阿旺曲沛' => ' a wàng qǔ pèi', + '允许误差' => ' yǔn xǔ wù chā', + '砚水壶儿' => ' yàn shuǐ hú r', + '运移时易' => ' yùn yí shí yì', + '绨袍之义' => ' tì páo zhī yì', + '载入史册' => ' zǎi rù shǐ cè', + '如狼似虎' => ' rú láng sì hǔ', + '扫地以尽' => ' sǎo dì yǐ jìn', + '石河子市' => ' shí hé zǐ shì', + '阿尔山市' => ' a ěr shān shì', + '凿坏以遁' => ' záo pī yǐ dùn', + '打心眼里' => ' dǎ xīn yǎn li', + '泽被后世' => ' zé pī hòu shì', + '味如鸡肋' => ' wèi rú jī lèi', + '少儿不宜' => ' shào ér bù yí', + '如胶似漆' => ' rú jiāo sì qī', + '如法炮制' => ' rú fǎ páo zhì', + '极右分子' => ' jí yòu fèn zǐ', + '啼饥号寒' => ' tí jī háo hán', + '为非作恶' => ' wéi fēi zuò è', + '朝不虑夕' => ' zhāo bù lǜ xī', + '扫地俱尽' => ' sǎo dì jù jìn', + '乐府诗集' => ' yuè fǔ shī jí', + '好色之徒' => ' hào sè zhī tú', + '阿肯色州' => ' a kěn sè zhōu', + '小步舞曲' => ' xiǎo bù wǔ qǔ', + '阿苏火山' => ' a sū huǒ shān', + '乐山大佛' => ' lè shān dà fó', + '踏踏实实' => ' tā tā shi shí', + '三闾大夫' => ' sān lǘ dài fū', + '斗粟尺布' => ' dǒu sù chǐ bù', + '小日本儿' => ' xiǎo rì běn r', + '卜昼卜夜' => ' bǔ zhòu bǔ yè', + '咳珠唾玉' => ' ké zhū tuò yù', + '如其所好' => ' rú qí suǒ hào', + '脊柱后凸' => ' jǐ zhù hòu tū', + '看不过去' => ' kàn bu guò qu', + '裸子植物' => ' luǒ zǐ zhí wù', + '吃里扒外' => ' chī lǐ pá wài', + '须眉男子' => ' xū méi nán zǐ', + '大陆漂移' => ' dà lù piāo yí', + '这早晚儿' => ' zhè zǎo wǎn r', + '赫鲁晓夫' => ' hè lǔ xiǎo fu', + '赞叹不已' => ' zàn tàn bù yǐ', + '劳筋苦骨' => ' láo jīn kǔ gǔ', + '纷纭杂沓' => ' fēn yún zá tà', + '曼切斯特' => ' màn qiē sī tè', + '发秃齿豁' => ' fà tū chǐ huò', + '列缺霹雳' => ' liè quē pī lì', + '必和必拓' => ' bì huó bì tuò', + '逐次近似' => ' zhú cì jìn sì', + '过去分词' => ' guò qù fèn cí', + '荆棘塞途' => ' jīng jí sè tú', + '分子医学' => ' fēn zǐ yī xué', + '浮白载笔' => ' fú bái zǎi bǐ', + '巴塞罗那' => ' bā sài luó nà', + '丝恩发怨' => ' sī ēn fà yuàn', + '来日大难' => ' lái rì dà nàn', + '胳臂肘儿' => ' gē bei zhǒu r', + '大不列蹀' => ' dà bu lie die', + '曲靖地区' => ' qǔ jìng dì qū', + '四邻八舍' => ' sì lín bā shè', + '自以为是' => ' zì yǐ wéi shì', + '自繇自在' => ' zì yóu zì zai', + '贩夫走卒' => ' fàn fū zǒu fú', + '畜妻养子' => ' xù qī yǎng zǐ', + '似漆如胶' => ' sì qī rú jiāo', + '杜莎夫人' => ' dù suō fū ren', + '自怨自艾' => ' zì yuàn zì yì', + '四马攒蹄' => ' sì mǎ cuán tí', + '贫富差距' => ' pín fù chā jù', + '巴巴结结' => ' bā bā jiē jiē', + '倒戢干戈' => ' dǎo jí gān gē', + '出臭子儿' => ' chū chòu zǐ r', + '似水如鱼' => ' sì shuǐ rú yú', + '贸易逆差' => ' mào yì nì chā', + '卷席而居' => ' juàn xí ér jū', + '大兴土木' => ' dà xīng tǔ mù', + '太阿倒持' => ' tài ē dào chí', + '牢什古子' => ' láo shí gǔ zi', + '弟男子侄' => ' dì nán zǐ zhí', + '拉枯折朽' => ' lā kū shé xiǔ', + '蒙帕纳斯' => ' měng pà nà sī', + '塞尔维亚' => ' sài ěr wéi yà', + '竖起耳朵' => ' shù qǐ ěr duo', + '削木为吏' => ' xuē mù wéi lì', + '逻辑错误' => ' luó ji cuò wù', + '金吾不禁' => ' jīn wú bù jìn', + '二三君子' => ' èr sān jūn zǐ', + '寻瑕伺隙' => ' xún xiá sì xì', + '尽如人意' => ' jìn rú rén yì', + '倒霉蛋儿' => ' dǎo méi dàn r', + '刻意为之' => ' kè yì wéi zhī', + '宴安酖毒' => ' yàn ān dān dú', + '四不拗六' => ' sì bù niù liù', + '雁泊人户' => ' yàn bó rén hù', + '单鹄寡凫' => ' dān hú guǎ fú', + '淡而不厌' => ' dàn ér bù yàn', + '胆大如斗' => ' dǎn dà rú dǒu', + '典妻鬻子' => ' diǎn qī yù zǐ', + '偃革倒戈' => ' yǎn gé dǎo gē', + '箪食壶酒' => ' dān sì hú jiǔ', + '代客泊车' => ' dài kè bó chē', + '穴居野处' => ' xué jū yě chǔ', + '儿童歌曲' => ' ér tóng gē qǔ', + '眼犄角儿' => ' yǎn jī jué ér', + '恶湿居下' => ' wù shī jū xià', + '胳膊肘子' => ' gē bo zhǒu zǐ', + '菲食薄衣' => ' fěi shí bó yī', + '差额选举' => ' chā é xuǎn jǔ', + '胡椒薄荷' => ' hú jiāo bò he', + '阿谀谄媚' => ' ē yú chǎn mèi', + '通都大邑' => ' tōng dū dà yì', + '释迦牟尼' => ' shì jiā mù ní', + '阿世取容' => ' ē shì qǔ róng', + '佛眼佛心' => ' fó yǎn fó xīn', + '似非而是' => ' sì fēi ér shì', + '大溪豆干' => ' dà xī dòu gān', + '言无不尽' => ' yán wú bù jìn', + '了无惧色' => ' liǎo wū jǔ sè', + '四子王旗' => ' sì zǐ wáng qí', + '佛罗伦萨' => ' fó luó lún sà', + '未知数儿' => ' wèi zhī shù r', + '佛法僧目' => ' fó fǎ sēng mù', + '腐败分子' => ' fǔ bài fēn zǐ', + '爵士音乐' => ' jué shì yīn yuè', + '六安地区' => ' lù ān dì qū', + '抓破脸子' => ' zhuā pò liǎn zǐ', + '各奔前程' => ' gè bèn qián chéng', + '受洗命名' => ' shòu xǐ mìng míng', + '少男少女' => ' shào nán shào nǔ:', + '论黄数黑' => ' lùn huáng shǔ hēi', + '心潮澎湃' => ' xīn cháo péng pài', + '各显所长' => ' gè xiǎn suǒ cháng', + '鸾只凤单' => ' luán zhī fèng dān', + '心电感应' => ' xīn diàn gǎn yìng', + '心灵感应' => ' xīn líng gǎn yìng', + '乱葬岗子' => ' luàn zàng gǎng zǐ', + '商业行为' => ' shāng yè xíng wéi', + '千载一圣' => ' qiān zǎi yī shèng', + '倒箧倾囊' => ' dǎo qiè qīng náng', + '攻过箴阙' => ' gōng guò zhēn què', + '其应若响' => ' qí yìng ruò xiǎng', + '高风劲节' => ' gāo fēng jìng jié', + '颠倒乾坤' => ' diān dǎo qián kūn', + '蒙古人种' => ' měng gǔ rén zhǒng', + '当着不着' => ' dāng zhuó bù zhuó', + '电子邮箱' => ' diàn zǐ yóu xiāng', + '磨盘两圆' => ' mò pán liǎng yuán', + '梦魂颠倒' => ' mèng hún diān dǎo', + '东量西折' => ' dōng liàng xī shé', + '缝纫车间' => ' féng rèn chē jiān', + '绕梁之音' => ' rǎo liáng zhī yīn', + '愁多夜长' => ' chóu duō yè cháng', + '横行直走' => ' héng xíng zhí zǒu', + '原子质量' => ' yuán zǐ zhì liàng', + '横殃飞祸' => ' hèng yāng fēi huò', + '应用数学' => ' yìng yòng shù xué', + '凤楼龙阙' => ' fèng lóu lóng què', + '人头攒动' => ' rén tóu cuán dòng', + '应运而生' => ' yìng yùn ér shēng', + '任性妄为' => ' rèn xìng wàng wéi', + '瓶沈簪折' => ' píng shěn zān shé', + '横征暴赋' => ' hèng zhēng bào fù', + '应用软体' => ' yìng yòng ruǎn tǐ', + '重纸累札' => ' chóng zhǐ lèi zhá', + '红不棱登' => ' hóng bù lēng dēng', + '老之将至' => ' lǎo zhī jiāng zhì', + '鸿鹄将至' => ' hóng hú jiāng zhì', + '强干弱枝' => ' qiáng gān ruò zhī', + '鸾漂凤泊' => ' luán piāo fèng bó', + '横抢武夺' => ' hèng qiǎng wǔ duó', + '流觞曲水' => ' liú shāng qǔ shuǐ', + '抢购一空' => ' qiāng gòu yī kōng', + '怒目相向' => ' nù mù xiāng xiàng', + '寡见鲜闻' => ' guǎ jiàn xiǎn wén', + '厝火燎原' => ' cuò huǒ liǎo yuán', + '寸有所长' => ' cùn yǒu suǒ cháng', + '寡廉鲜耻' => ' guǎ lián xiǎn chǐ', + '流水游龙' => ' liú shuǐ yóu lóng', + '只争朝夕' => ' zhǐ zhēng zhāo xī', + '六畜兴旺' => ' liù chù xīng wàng', + '更仆难终' => ' gēng pú nán zhōng', + '凌霄之志' => ' líng xiāo zhī zhì', + '电子手表' => ' diàn zǐ shǒu biǎo', + '患难之交' => ' huàn nàn zhī jiāo', + '零零散散' => ' líng líng sǎn sǎn', + '弃短就长' => ' qì duǎn jiù cháng', + '榱栋崩折' => ' cuī dòng bēng shé', + '榱崩栋折' => ' cuī bēng dòng shé', + '观者成堵' => ' guān zhě chéng dǔ', + '裂冠毁冕' => ' liè guàn huǐ miǎn', + '倒山倾海' => ' dǎo shān qīng hǎi', + '功遂身退' => ' gōng suí shēn tuì', + '前程似锦' => ' qián chéng sì jǐn', + '少说为佳' => ' shǎo shuō wéi jiā', + '满天星斗' => ' mǎn tiān xīng dǒu', + '前功尽废' => ' qián gōng jìn fèi', + '签订合同' => ' qiān dìng hé tong', + '高山反应' => ' gāo shān fǎn yìng', + '前功尽灭' => ' qián gōng jìn miè', + '更阑人静' => ' gēng lán rén jǐng', + '昧旦晨兴' => ' mèi dàn chún xīng', + '满腔热枕' => ' mǎn qiāng rè chén', + '公共管理' => ' gōng gòng guǎn lǐ', + '合众银行' => ' hé zhòng yín háng', + '潜孔钻机' => ' qián kǒng zuàn jī', + '更深夜静' => ' gēng shēn yè jìng', + '更生霉素' => ' gēng shēng méi sù', + '吉人天相' => ' jí rén tiān xiàng', + '更弦改辙' => ' gēng xián gǎi zhé', + '马瘦毛长' => ' mǎ shòu máo cháng', + '尺短寸长' => ' chǐ duǎn cù cháng', + '捋袖揎拳' => ' luō xiù xuān quán', + '弹尽粮绝' => ' dàn jìn liáng jué', + '凤泊鸾漂' => ' fèng bó luán piāo', + '光杆司令' => ' guāng gǎn sī lìng', + '好行小惠' => ' hào xíng xiǎo huì', + '传为美谈' => ' chuán wéi měi tán', + '传为佳话' => ' chuán wéi jiā huà', + '好谋善断' => ' hào móu shàn duàn', + '铺床叠被' => ' pū chuáng dié bèi', + '形单影只' => ' xíng dān yǐng zhī', + '地久天长' => ' dì jiǔ tiān cháng', + '传柄移藉' => ' chuán bǐng yí jiè', + '秋行夏令' => ' qiū xíng xià líng', + '呵欠连天' => ' hē qiàn lián tiān', + '连车平斗' => ' lián chē píng dǒu', + '酩酊烂醉' => ' mǐng dǐng làn zuì', + '鼎铛有耳' => ' dǐng chēng yǒu ěr', + '曲水流觞' => ' qǔ shuǐ liú shāng', + '处实效功' => ' chǔ shí xiào gōng', + '楞眉横眼' => ' lèng méi héng yǎn', + '累月经年' => ' lěi yuè jīng nián', + '力能扛鼎' => ' lì néng gāng dǐng', + '冥行擿埴' => ' míng xíng zhì zhí', + '好梦不长' => ' hǎo mèng bù cháng', + '刁钻促搯' => ' diāo zuàn cù chāo', + '干干净净' => ' gàn gān jìng jìng', + '伤痕累累' => ' shāng hén léi léi', + '谋臣武将' => ' móu chén wǔ jiàng', + '温衾扇枕' => ' wēn qīn shān zhěn', + '变态反应' => ' biàn tài fǎn yìng', + '直柄钻头' => ' zhí bǐng zuàn tóu', + '电子信箱' => ' diàn zǐ xìn xiāng', + '蜗杆传动' => ' wō gǎn chuán dòng', + '散兵游勇' => ' sǎn bīng yóu yǒng', + '植发穿冠' => ' zhí fà chuān guàn', + '月中折桂' => ' yuè zhōng shé guì', + '反应时间' => ' fǎn yìng shí jiān', + '传道受业' => ' chuán dào shòu yè', + '植发冲冠' => ' zhí fà chōng guàn', + '云合响应' => ' yún hé xiǎng yìng', + '文子同升' => ' wén zǐ tóng shēng', + '影只形单' => ' yǐng zhī xíng dān', + '十里长亭' => ' shí lǐ cháng tíng', + '狼艰狈蹶' => ' láng jiān bèi juě', + '行号巷哭' => ' xíng háo xiàng kū', + '敛容屏气' => ' liǎn róng bǐng qì', + '行行蛇蚓' => ' háng háng shé yǐn', + '吹拉弹唱' => ' chuī lā tán chàng', + '日短心长' => ' rì duǎn xīn cháng', + '商业银行' => ' shāng yè yín háng', + '日久天长' => ' rì jiǔ tiān cháng', + '浪子宰相' => ' làng zǐ zǎi xiàng', + '重生父母' => ' chóng shēng fù mǔ', + '东墙处子' => ' dōng qiáng chǔ zǐ', + '卷土重来' => ' juǎn tǔ chóng lái', + '老老少少' => ' lǎo lǎo shào shào', + '弹性模量' => ' tán xìng mó liàng', + '重明继焰' => ' chóng míng jì yàn', + '充类至尽' => ' chōng lèi zhì jìn', + '垂死挣扎' => ' chuí sǐ zhēng zhá', + '重金袭汤' => ' chóng jīn xí tāng', + '重金兼紫' => ' chóng jīn jiān zǐ', + '冲击钻头' => ' chōng jī zuàn tóu', + '戎马倥偬' => ' róng mǎ kǒng zǒng', + '后生小子' => ' hòu shēng xiǎo zǐ', + '喟然长叹' => ' kuì rán cháng tàn', + '喉长气短' => ' hóu cháng qì duǎn', + '却老还童' => ' què lǎo huán tóng', + '重手累足' => ' chóng shǒu lěi zú', + '横恩滥赏' => ' hèng ēn làn shǎng', + '吹花嚼蕊' => ' chuī huā jiáo ruǐ', + '改行为善' => ' gǎi xíng wéi shàn', + '扛鼎拔山' => ' gāng dǐng bá shān', + '了身达命' => ' liǎo shēn dá mìng', + '了然于胸' => ' liǎo rán yú xiōng', + '感应电流' => ' gǎn yìng diàn liú', + '了了可见' => ' liǎo liǎo kě jiàn', + '桂子飘香' => ' guì zǐ piāo xiāng', + '撩蜂吃螫' => ' liáo fēng chī shì', + '干霄凌云' => ' gān xiāo líng yún', + '了不长进' => ' liǎo bù zhǎng jǐn', + '擎天之柱' => ' qíng tiān zhī zhù', + '琼楼金阙' => ' qióng lóu jīn què', + '两世为人' => ' liǎng shì wéi rén', + '国之干城' => ' guó zhī gān chéng', + '电子元件' => ' diàn zǐ yuán jiàn', + '影像处理' => ' yǐng xiàng chǔ lǐ', + '海相沉积' => ' hǎi xiàng chén jī', + '穷途潦倒' => ' qióng tú liáo dǎo', + '反败为胜' => ' fǎn bài wéi shèng', + '穷理尽性' => ' qióng lǐ jìn xìng', + '电子天平' => ' diàn zǐ tiān píng', + '受降仪式' => ' shòu xiáng yí shì', + '一箭上垛' => ' yī jiàn shàng duò', + '喙长三尺' => ' huì cháng sān chǐ', + '黄干黑廋' => ' huáng gān hēi sōu', + '黄冠草服' => ' huáng guàn cǎo fú', + '黄冠草履' => ' huáng guàn cǎo lǚ', + '栋折榱坏' => ' dòng shé cuī huài', + '黄雀伺蝉' => ' huáng què sì chán', + '骈兴错出' => ' pián xīng cuò chū', + '戒奢宁俭' => ' jiè shē nìng jiān', + '空腹便便' => ' kōng fù pián pián', + '借尸还阳' => ' jiè shī huán yáng', + '还元返本' => ' huán yuán fǎn běn', + '盛水不漏' => ' chéng shuǐ bù lòu', + '长念却虑' => ' cháng niàn què lǜ', + '分分秒秒' => ' fèn fēn miǎo miǎo', + '长篇大论' => ' cháng piān dà lùn', + '翩翩公子' => ' piān piān gōng zǐ', + '毁钟为铎' => ' huǐ zhōng wéi duó', + '镌脾琢肾' => ' juān pí zhuó shèn', + '看清形势' => ' kān qīng xíng shì', + '溘然长往' => ' kè rán cháng wǎng', + '斗量筲计' => ' dǒu liáng shāo jì', + '诘戎治兵' => ' jié róng zhì bīng', + '强人所难' => ' qiǎng rén suǒ nán', + '深切著明' => ' shēn qiè zhù míng', + '天长日久' => ' tiān cháng rì jiǔ', + '江翻海倒' => ' jiāng fān hǎi dǎo', + '静影沉璧' => ' jing ying chen bi', + '参商之虞' => ' shēn shāng zhī yú', + '经验教训' => ' jīng yàn jiào xun', + '天人感应' => ' tiān rén gǎn yìng', + '径行直遂' => ' jìng xíng zhí suí', + '长绳系日' => ' cháng shéng jì rì', + '千载难逢' => ' qiān zǎi nán féng', + '鸟面鹄形' => ' niǎo miàn hú xíng', + '身无长处' => ' shēn wú cháng chù', + '返本还源' => ' fǎn běn huán yuán', + '短叹长吁' => ' duǎn tàn cháng xū', + '声应气求' => ' shēng yìng qì qiú', + '旁引曲证' => ' páng yǐn qǔ zhèng', + '度长絜短' => ' dù cháng xié duǎn', + '沉谋重虑' => ' chén móu chóng lǜ', + '魂颠梦倒' => ' hún diān mèng dǎo', + '充分利用' => ' chōng fèn lì yòng', + '江淹才尽' => ' jiāng yān cái jìn', + '乘肥衣轻' => ' chéng féi yì qīng', + '斗方名士' => ' dǒu fāng míng shì', + '绝长继短' => ' jué cháng jì duǎn', + '倔头强脑' => ' juè tóu jiàng nǎo', + '撅坑撅堑' => ' jué kēng jué qiàn', + '截长补短' => ' jié cháng bǔ duǎn', + '藉草枕块' => ' jiè cǎo zhěn kuài', + '教猱升木' => ' jiāo náo shēng mù', + '称德度功' => ' chēng dé duó gōng', + '成本会计' => ' chéng běn kuài jì', + '绝长补短' => ' jué cháng bǔ duǎn', + '绝长续短' => ' jué cháng xù duǎn', + '山鸣谷应' => ' shān míng gǔ yìng', + '截铁斩钉' => ' jié tiě zhǎn dìng', + '舍短取长' => ' shě duǎn qǔ cháng', + '乘利席胜' => ' chéng lì xí shèng', + '长篇大套' => ' cháng piān dà tào', + '活剥生吞' => ' huó bāo shēng tūn', + '干扁豆角' => ' gān biǎn dòu jiǎo', + '昏镜重磨' => ' hūn jìng chóng mó', + '山行海宿' => ' shān xíng hǎi xiǔ', + '框架结构' => ' kuàng jià jié gòu', + '撒豆成兵' => ' sǎ dòu chéng bīng', + '狂风怒号' => ' kuáng fēng nù háo', + '冲冠眦裂' => ' chōng guàn zì liè', + '鹄形鸟面' => ' hú xíng niǎo miàn', + '鹄峙鸾翔' => ' hú zhì luán xiáng', + '竭诚尽节' => ' jié chéng jìn jié', + '东山之志' => ' dōng shān zhī zhì', + '若崩厥角' => ' ruò bēng jué jiǎo', + '充分发展' => ' chōng fèn fā zhǎn', + '房贷银行' => ' fáng dài yín háng', + '兜肚连肠' => ' dōu dǔ lián cháng', + '失惊倒怪' => ' shī jīng dǎo guài', + '还年却老' => ' huán nián què lǎo', + '什锦炒面' => ' shí jǐn chǎo miàn', + '三差两错' => ' sān chā liǎng cuò', + '重复使用' => ' chóng fù shǐ yòng', + '三长四短' => ' sān cháng sì duǎn', + '坏裳为裤' => ' huài shang wéi kù', + '杀出重围' => ' shā chū chóng wéi', + '盘水加剑' => ' pan shui jia jian', + '静电干扰' => ' jìng diàn gān rǎo', + '长谈阔论' => ' cháng tán kuò lùn', + '广寒仙子' => ' guǎng hán xiān zǐ', + '长途车站' => ' cháng tú chē zhàn', + '大人先生' => ' dà rén xiān sheng', + '掂斤抹两' => ' diān jīn mò liǎng', + '户限为穿' => ' hù xiàn wéi chuān', + '高原反应' => ' gāo yuán fǎn yìng', + '长途飞行' => ' cháng tú fēi xíng', + '神哗鬼叫' => ' shén huá guǐ jiào', + '家道从容' => ' jiā dào cōng róng', + '尽诚竭节' => ' jìn chéng jié jié', + '承销利差' => ' chéng xiāo lì chā', + '颠乾倒坤' => ' diān qiān dǎo kūn', + '甲冠天下' => ' jiǎ guàn tiān xià', + '好景不长' => ' hǎo jǐng bù cháng', + '挟势弄权' => ' jiā shì nòng quán', + '奉子成婚' => ' fèng zǐ chéng hūn', + '家长里短' => ' jiā cháng lǐ duǎn', + '津关险塞' => ' jīn guān xiǎn sài', + '挟主行令' => ' jiā zhǔ xíng lìng', + '斗筲穿窬' => ' dǒu shāo chuān yú', + '龙楼凤阙' => ' lóng lóu fèng què', + '龙兴凤举' => ' lóng xīng fèng jǔ', + '间接经验' => ' jiàn jiē jīng yàn', + '颠倒衣裳' => ' diān dǎo yī cháng', + '啜菽饮水' => ' chuò shū yǐn shuǐ', + '倾肠倒肚' => ' qīng cháng dào dǔ', + '悄然无声' => ' qiǎo rán wú shēng', + '掂梢折本' => ' diān shāo shé běn', + '共为唇齿' => ' gòng wéi chún chǐ', + '鸾凤和鸣' => ' luán fèng hè míng', + '强食靡角' => ' qiǎng shí mí jiǎo', + '当务始终' => ' dang wu shi zhong', + '颠倒阴阳' => ' diān dǎo yīn yáng', + '弹冠结绶' => ' tán guān jié shòu', + '颠颠倒倒' => ' diān diān dǎo dǎo', + '顾虑重重' => ' gù lǜ chóng chóng', + '党豺为虐' => ' dǎng chái wéi nüè', + '梦撒撩丁' => ' mèng sā liáo dīng', + '猛将如云' => ' měng jiàng rú yún', + '强作解人' => ' qiǎng zuò jiě rén', + '电力供应' => ' diàn lì gōng yìng', + '股票行情' => ' gǔ piào háng qíng', + '龙兴云属' => ' lóng xīng yún shǔ', + '旧雨重逢' => ' jiù yǔ chóng féng', + '年轻有为' => ' nián qīng yǒu wéi', + '能不称官' => ' néng bù chèn guān', + '发上指冠' => ' fà shàng zhǐ guān', + '翻黄倒皂' => ' fān huáng dǎo zào', + '锦囊还矢' => ' jǐn náng huán shǐ', + '发植穿冠' => ' fà zhí chuān guān', + '内部调整' => ' nèi bù tiáo zhěng', + '动态更新' => ' dòng tài gēng xīn', + '强嘴拗舌' => ' jiàng zuǐ niù shé', + '盛必虑衰' => ' shèng bì lǜ shuāi', + '捻土为香' => ' niǎn tǔ wéi xiāng', + '动词重叠' => ' dòng cí chóng dié', + '长枕大被' => ' cháng zhěn dà bèi', + '遁迹黄冠' => ' dùn jì huáng guàn', + '强嘴硬牙' => ' jiàng zuǐ yìng yá', + '顿足椎胸' => ' dùn zú zhuī xiōng', + '生理反应' => ' shēng lǐ fǎn yìng', + '声求气应' => ' shēng qiú qì yìng', + '天长地久' => ' tiān cháng dì jiǔ', + '声势显赫' => ' shēng shì xiǎn hè', + '发短心长' => ' fà duǎn xīn cháng', + '侔色揣称' => ' móu sè chuǎi chèn', + '参辰卯酉' => ' shēn chén mǎo yǒu', + '强迫劳动' => ' qiǎng pò láo dòng', + '车削加工' => ' chē xiāo jiā gōng', + '袅袅娜娜' => ' niǎo niǎo nuó nuó', + '皮相之见' => ' pí xiàng zhī jiàn', + '化学成分' => ' huà xué chéng fèn', + '命名系统' => ' mìng míng xì tǒng', + '竭忠尽智' => ' jié zhōng jìn zhì', + '居轴处中' => ' jū zhóu chǔ zhōng', + '焦唇干肺' => ' jiāo chún gān fèi', + '急景凋年' => ' jí yǐng diāo nián', + '蛇鼠横行' => ' shé shǔ héng xíng', + '非分之想' => ' fēi fèn zhī xiǎng', + '卷甲衔枚' => ' juàn jiǎ xián méi', + '卷甲束兵' => ' juàn jiǎ shù bīng', + '吵吵闹闹' => ' chāo chao nào nào', + '长枕大衾' => ' cháng zhěn dà qīn', + '极限量规' => ' jí xiàn liáng guī', + '汇丰银行' => ' huì fēng yín háng', + '舌咽神经' => ' shé yān shén jīng', + '竭智尽忠' => ' jié zhì jìn zhōng', + '长斋绣佛' => ' cháng zhāi xiù fó', + '电子空间' => ' diàn zǐ kōng jiān', + '翻江倒海' => ' fān jiāng dǎo hǎi', + '长篇累牍' => ' cháng piān lěi dú', + '率土宅心' => ' shuài tǔ zhái xīn', + '盈千累万' => ' yíng qiān lěi wàn', + '缠绵蕴藉' => ' chán mián yùn jiè', + '搀行夺市' => ' chān háng duó shì', + '层见错出' => ' céng xiàn cuò chū', + '勇冠三军' => ' yǒng guàn sān jūn', + '沧浪老人' => ' cāng láng lǎo rén', + '竖子成名' => ' shù zǐ chéng míng', + '应变无方' => ' yìng biàn wú fāng', + '残军败将' => ' cán jūn bài jiàng', + '钻天觅缝' => ' zuàn tiān mì féng', + '束椽为柱' => ' shù chuán wéi zhù', + '天长地老' => ' tiān cháng dì lǎo', + '泊船瓜洲' => ' bó chuán guā zhōu', + '苦难深重' => ' kǔ nàn shēn zhòng', + '银行存款' => ' yín háng cún kuǎn', + '朝鲜半岛' => ' cháo xiǎn bàn dǎo', + '转嗔为喜' => ' zhuǎn chēn wéi xǐ', + '陂湖禀量' => ' bēi hú bǐng liáng', + '长才短驭' => ' cháng cái duǎn yù', + '数白论黄' => ' shǔ bái lùn huáng', + '有三有俩' => ' yǒu sān yǒu liǎng', + '用其所长' => ' yòng qí suǒ cháng', + '友好相处' => ' yǒu hǎo xiāng chǔ', + '二重下标' => ' èr chóng xià biāo', + '深源地震' => ' shēn yuán dì zhèn', + '薪尽火传' => ' xīn jìn huǒ chuán', + '饮水啜菽' => ' yǐn shuǐ chuò shū', + '钻洞觅缝' => ' zuàn dòng mì féng', + '蓝田种玉' => ' lán tián zhòng yù', + '双柑斗酒' => ' shuài gān dǒu jiǔ', + '油炸圈饼' => ' yóu zhá quān bǐng', + '长材茂学' => ' cháng cái mào xué', + '长驾远驭' => ' cháng jià yuǎn yù', + '应用化学' => ' yìng yòng huà xué', + '万古长青' => ' wàn gǔ cháng qīng', + '洋场恶少' => ' yáng chǎng è shào', + '万应灵丹' => ' wàn yìng líng dān', + '应时对景' => ' yìng shí duì jǐng', + '长春不老' => ' cháng chún bù lǎo', + '收拾收拾' => ' shōu shi shōu shi', + '烧香拜佛' => ' shāo xiāng bài fó', + '切片检查' => ' qiē piàn jiǎn chá', + '拳头产品' => ' quán tou chǎn pǐn', + '银行贷款' => ' yín háng dài kuǎn', + '挑灯夜战' => ' tiǎo dēng yè zhàn', + '水刑逼供' => ' shuǐ xíng bī gòng', + '朝鲜海峡' => ' cháo xiǎn hǎi xiá', + '温室效应' => ' wēn shì xiào yìng', + '弹空说嘴' => ' tán kōng shuō zuǐ', + '兵不由将' => ' bīng bù yóu jiàng', + '人种差别' => ' rén zhǒng chā bié', + '银行汇票' => ' yín háng huì piào', + '转辗反侧' => ' zhuǎn zhǎn fǎn cè', + '挑战者号' => ' tiǎo zhàn zhě hào', + '民穷财尽' => ' mín qióng cái jìn', + '摽梅之年' => ' biào mén zhī nián', + '火烧火燎' => ' huǒ shāo huǒ liǎo', + '弹冠振衿' => ' tán guān zhèn jīn', + '辩证逻辑' => ' biàn zhèng luó ji', + '炎性反应' => ' yán xìng fǎn yìng', + '损军折将' => ' sǔn jūn zhé jiàng', + '膀胱气化' => ' páng guāng qì huà', + '屏气凝神' => ' bǐng qì níng shén', + '摒弃前嫌' => ' bìng qì qián xián', + '谈言微中' => ' tán yán wēi zhòng', + '白衣卿相' => ' bái yī qīng xiàng', + '事后聪明' => ' shì hòu cōng ming', + '转愁为喜' => ' zhuǎn chóu wéi xǐ', + '杠杆收购' => ' gàng gǎn shōu gòu', + '著作等身' => ' zhù zuò děng shēn', + '逾墙钻穴' => ' yú qiáng zuàn xué', + '歪打正着' => ' wāi dǎ zhèng zháo', + '蟏蛸满室' => ' xiāo shāo mǎn shì', + '特种警察' => ' tè zhòng jǐng chá', + '杼柚之空' => ' zhù zhóu zhī kōng', + '褎然冠首' => ' yòu rán guàn shǒu', + '白手兴家' => ' bái shǒu xīng jiā', + '白首为郎' => ' bái shǒu wéi láng', + '百兽率舞' => ' bǎi shòu shuài wǔ', + '伴食宰相' => ' bàn shí zǎi xiàng', + '松松散散' => ' sōng sōng sǎn sǎn', + '鼻孔撩天' => ' bí kǒng liáo tiān', + '人行横道' => ' rén xíng héng dào', + '水浒后传' => ' shuǐ hǔ hòu zhuàn', + '薮中荆曲' => ' sǒu zhōng jīng qǔ', + '不遑宁处' => ' bù huáng níng chǔ', + '不良反应' => ' bù liáng fǎn yìng', + '长夜难明' => ' cháng yè nán míng', + '鬼使神差' => ' guǐ shǐ shén chāi', + '调频电台' => ' tiáo pín diàn tái', + '诱掖奖劝' => ' yòu yè jiǎng quàn', + '行侠仗义' => ' xìng xiá zhàng yì', + '挑牙料唇' => ' tiǎo yá liào chún', + '拔山扛鼎' => ' bá shān gāng dǐng', + '龙生九子' => ' lóng shēng jiǔ zǐ', + '铢两悉称' => ' zhū liǎng xī chèn', + '鱼与熊掌' => ' yú yǔ xióng zhǎng', + '兴妖作怪' => ' xīng yāo zuò guài', + '朝阳产业' => ' zhāo yáng chǎn yè', + '兴奋高潮' => ' xīng fèn gāo cháo', + '高高兴兴' => ' gāo gāo xìng xīng', + '公诸同好' => ' gōng zhū tóng hào', + '终焉之志' => ' zhōng yān zhī zhì', + '高空弹跳' => ' gāo kōng tán tiào', + '外公切线' => ' wài gōng qiē xiàn', + '众怨之的' => ' zhòng yuàn zhī dì', + '臭味相投' => ' xiù wèi xiāng tóu', + '插不上手' => ' chā bu shàng shǒu', + '白发千丈' => ' bái fà qiān zhàng', + '意味深长' => ' yì wèi shēn cháng', + '调养身体' => ' tiáo yǎng shēn tǐ', + '一字长城' => ' yī zì cháng chéng', + '牵羊担酒' => ' qiān yáng dàn jiǔ', + '败军之将' => ' bài jūn zhī jiàng', + '调朱弄粉' => ' tiáo zhū nòng fěn', + '切中要害' => ' qiē zhōng yào hài', + '调脂弄粉' => ' tiáo zhī nòng fěn', + '卫满朝鲜' => ' wèi mǎn cháo xiǎn', + '援助之手' => ' yuán zhù zhī shǒu', + '暗箭中人' => ' àn jiàn zhòng rén', + '了如指掌' => ' liǎo rú zhǐ zhǎng', + '调风变俗' => ' tiáo fēng biàn sú', + '著述等身' => ' zhù shù děng shēn', + '天下为公' => ' tiān xià wéi gōng', + '主要成分' => ' zhǔ yào chéng fèn', + '卫氏朝鲜' => ' wèi shì cháo xiǎn', + '狼狈为奸' => ' láng bèi wéi jiān', + '了却此生' => ' liǎo què cǐ shēng', + '天下为笼' => ' tiān xià wéi lóng', + '筑坛拜将' => ' zhù tán bài jiàng', + '自奉甚俭' => ' zì fèng shèn jiǎn', + '中间部分' => ' zhōng jiān bù fen', + '招降纳叛' => ' zhāo xiáng nà pàn', + '钻山塞海' => ' zuàn shān sāi hǎi', + '当世之冠' => ' dāng shì zhī guàn', + '黄埔军校' => ' huáng pǔ jūn xiào', + '麟角凤觜' => ' lín jiǎo fèng zuǐ', + '衣锦还乡' => ' yì jǐn huán xiāng', + '天道好还' => ' tiān dào hǎo huán', + '占风望气' => ' zhān fēng wàng qì', + '挂在嘴上' => ' guà zai zuǐ shang', + '水果罐头' => ' shuǐ guǒ guàn tóu', + '裁长补短' => ' cái cháng bǔ duǎn', + '黑汗王朝' => ' hēi hán wáng cháo', + '钻坚研微' => ' zuàn jiān yán wēi', + '不胜杯杓' => ' bù shèng bēi sháo', + '水宿风餐' => ' shuǐ xiǔ fēng cān', + '沉没成本' => ' chén mò chéng běn', + '解发佯狂' => ' jiě fà yáng kuáng', + '着着失败' => ' zhuó zhuó shī bài', + '不甚了了' => ' bù shèn liǎo liǎo', + '招揽生意' => ' zhāo lǎn shēng yi', + '止咳糖浆' => ' zhǐ ké táng jiāng', + '痛自创艾' => ' tòng zì chuāng yì', + '公共关系' => ' gōng gòng guān xì', + '令人兴奋' => ' lìng rén xīng fèn', + '公共开支' => ' gōng gòng kāi zhī', + '见闻有限' => ' jiàn wén yǒu xiàn', + '重铬酸钾' => ' chóng gè suān jiǎ', + '公共设施' => ' gōng gòng shè shī', + '逾墙钻蠙' => ' yú qiáng zuàn pín', + '高村正彦' => ' gāo cūn zhēng yàn', + '调嘴调舌' => ' tiáo zuǐ diào shé', + '鸾飘凤泊' => ' luán piāo fèng bó', + '调嘴弄舌' => ' tiáo zuǐ nòng shé', + '鼎铛玉石' => ' dǐng chēng yù shí', + '铁板钉钉' => ' tiě bǎn dìng dīng', + '安常守分' => ' ān cháng shǒu fèn', + '恫瘝在抱' => ' tōng guān zài bào', + '安常处顺' => ' ān cháng chǔ shùn', + '铢量寸度' => ' zhū liáng cùn duó', + '矮人观场' => ' ǎi rén guān cháng', + '同恶相助' => ' tóng wù xiāng zhù', + '下旋削球' => ' xià xuán xiāo qíu', + '天地长久' => ' tiān dì cháng jiǔ', + '公共团体' => ' gōng gòng tuán tǐ', + '识明智审' => ' shí míng zhì shěn', + '惟肖惟妙' => ' wéi xiāo wéi miào', + '翻箱倒箧' => ' fān xiāng dǎo qiè', + '智穷才尽' => ' zhì qióng cái jìn', + '真相大白' => ' zhēn xiàng dà bái', + '眼不转睛' => ' yǎn bù zhuàn jīng', + '月落参横' => ' yuè luò shēn héng', + '质量要求' => ' zhì liàng yāo qiú', + '支链反应' => ' zhī liàn fǎn yìng', + '止咳平喘' => ' zhǐ ké píng chuǎn', + '先王之乐' => ' xiān wáng zhī yuè', + '聪明过头' => ' cōng ming guò tóu', + '月经失调' => ' yuè jīng shī tiáo', + '音乐光碟' => ' yīn yuè guāng dié', + '腰椎间盘' => ' yāo zhuī jiān pán', + '雨顺风调' => ' yǔ shùn fēng tiáo', + '刓方为圆' => ' shū fāng wéi yuán', + '万古长春' => ' wàn gǔ cháng chūn', + '尽释前嫌' => ' jìn shì qián xián', + '万箭攒心' => ' wàn jiàn cuán xīn', + '风调雨顺' => ' fēng tiáo yǔ shùn', + '凶相毕露' => ' xiōng xiàng bì lù', + '衣轻乘肥' => ' yì qīng chéng féi', + '占风使帆' => ' zhān fēng shǐ fān', + '相依为命' => ' xiāng yī wéi mìng', + '宿水餐风' => ' xiǔ shuǐ cān fēng', + '红泥月亮' => ' hóng ní yuè liang', + '郢书燕说' => ' yǐng shū yān shuō', + '兴妖作乱' => ' xīng yāo zuò luàn', + '饶舌调唇' => ' ráo shé tiáo chún', + '数黄道黑' => ' shu huang dao hei', + '云集响应' => ' yún jí xiǎng yìng', + '置水之情' => ' zhì shuǐ zhī qíng', + '相向突击' => ' xiāng xiàng tū jī', + '青年旅舍' => ' qīng nián lǔ: shè', + '委曲成全' => ' wěi qǔ chéng quán', + '为人正直' => ' wéi rén zhèng zhí', + '光阴似箭' => ' guāng yīn sì jiàn', + '相对位置' => ' xiāng duì wèi zhi', + '语境效应' => ' yǔ jìng xiào yìng', + '鸢肩鹄颈' => ' yuān jiān hú jǐng', + '青藏公路' => ' qīng zàng gōng lù', + '直接了当' => ' zhí jiē liǎo dàng', + '万头攒动' => ' wàn tóu cuán dòng', + '两肋插刀' => ' liǎng lèi chā dāo', + '形只影单' => ' xíng zhī yǐng dān', + '一长半短' => ' yī cháng bàn duǎn', + '间谍活动' => ' jiàn dié huó dòng', + '神差鬼使' => ' shén chāi guǐ shǐ', + '真命天子' => ' zhēn mìng tiān zǐ', + '神魂颠倒' => ' shén hún diān dǎo', + '位置效应' => ' wèi zhì xiào yìng', + '真龙天子' => ' zhēn lóng tiān zǐ', + '间接证据' => ' jiàn jiē zhèng jù', + '贞观之治' => ' zhēn guān zhī zhì', + '折长补短' => ' zhé cháng bǔ duǎn', + '正冠李下' => ' zhèng guàn lǐ xià', + '长途电话' => ' cháng tú diàn huà', + '间歇训练' => ' jiàn xiē xùn liàn', + '充分考虑' => ' chōng fèn kǎo lù:', + '超敏反应' => ' chāo mǐn fǎn yìng', + '似曾相识' => ' sì céng xiāng shí', + '翻箱倒柜' => ' fān xiāng dǎo guì', + '调研人员' => ' tiáo yán rén yuán', + '伴随效应' => ' bàn suí xiào yìng', + '车载斗量' => ' chē zài dǒu liáng', + '蒸沙为饭' => ' zhēng shā wéi fàn', + '音乐之声' => ' yīn yuè zhī shēng', + '访问方式' => ' fǎng wèn fāng shì', + '两性差距' => ' liǎng xìng chā jù', + '直截了当' => ' zhí jié liǎo dàng', + '枉口嚼舌' => ' wǎng kǒu jiáo shé', + '头晕脑涨' => ' tóu yūn nǎo zhàng', + '汪洋闳肆' => ' wāng yáng hóng sì', + '望子成才' => ' wàng zǐ chéng cái', + '头昏脑涨' => ' tóu hūn nǎo zhàng', + '预防接种' => ' yù fáng jiē zhòng', + '直捷了当' => ' zhí jié liǎo dàng', + '正式合同' => ' zhèng shì hé tong', + '两侧对称' => ' liǎng cè duì chèn', + '数见不鲜' => ' shuò jiàn bù xiān', + '置换反应' => ' zhì huàn fǎn yìng', + '调和振动' => ' tiáo hé zhèn dòng', + '似鸟恐龙' => ' sì niǎo kǒng lóng', + '应用系统' => ' yìng yòng xì tǒng', + '五陵年少' => ' wǔ líng nián shào', + '执鞭随蹬' => ' zhí biān suí dèng', + '阿甘正传' => ' a gān zhèng zhuàn', + '战争贩子' => ' zhàn zhēng fàn zǐ', + '行政干预' => ' xíng zhèng gān yù', + '遥相呼应' => ' yáo xiāng hū yìng', + '朝乾夕愓' => ' zhāo qián xī dàng', + '长辔远驭' => ' cháng pèi yuǎn yù', + '更有甚者' => ' gèng yǒu shèn zhě', + '长袖善舞' => ' cháng xiù shàn wǔ', + '科学种田' => ' kē xué zhòng tián', + '一鞭先著' => ' yī biān xiān zhuó', + '长生不死' => ' cháng shēng bū sǐ', + '辗转反侧' => ' zhǎn zhuǎn fǎn cè', + '斗转星移' => ' dǒu zhuǎn xīng yí', + '夜静更深' => ' yè jìng gēng shēn', + '倒海翻江' => ' dǎo hǎi fān jiāng', + '朝夕相处' => ' zhāo xī xiāng chǔ', + '长乐公主' => ' cháng lè gōng zhǔ', + '先我着鞭' => ' xiān wǒ zhuó biān', + '闲言长语' => ' xián yán cháng yǔ', + '长期饭票' => ' cháng qī fàn piào', + '长期共存' => ' cháng qī gòng cún', + '更新换代' => ' gēng xīn huàn dài', + '相时而动' => ' xiàng shí ér dòng', + '数黑论黄' => ' shǔ hēi lùn huáng', + '羊肠九曲' => ' yáng cháng jiǔ qǔ', + '长乐未央' => ' cháng lè wèi yāng', + '心长发短' => ' xīn cháng fà duǎn', + '摇头晃脑' => ' yáo tóu huàng nǎo', + '小子后生' => ' xiǎo zǐ hòu shēng', + '长命富贵' => ' cháng mìng fù guì', + '长吁短叹' => ' cháng xū duǎn tàn', + '朝梁暮晋' => ' zhāo liáng mù jìn', + '转浑天仪' => ' zhuàn hún tiān yí', + '中箭落马' => ' zhòng jiàn luò mǎ', + '转弯抹角' => ' zhuǎn wān mò jiǎo', + '管弦乐队' => ' guǎn xián yuè duì', + '心长力短' => ' xīn cháng lì duǎn', + '铁血宰相' => ' tiě xuè zǎi xiàng', + '朝穿暮塞' => ' zhāo chuān mù sāi', + '遥呼相应' => ' yáo hū xiāng yìng', + '咬钉嚼铁' => ' yǎo dīng jiáo tiě', + '朝成夕毁' => ' zhāo chéng xī huǐ', + '镜框舞台' => ' jìng kuàng wǔ tái', + '返老还童' => ' fǎn lǎo huán tóng', + '链式反应' => ' liàn shì fǎn yìng', + '铺张浪费' => ' pū zhāng làng fèi', + '夜长梦多' => ' yè cháng mèng duō', + '兆载永劫' => ' zhào zǎi yǒng jié', + '燕石妄珍' => ' yān shí wàng zhēn', + '保角对应' => ' bǎo jiǎo duì yìng', + '重文轻武' => ' chóng wén qīng wǔ', + '退耕还林' => ' tuì gēng huán lín', + '曾参杀人' => ' zēng shēn shā rén', + '悬梁自尽' => ' xuán liáng zì jìn', + '朝成暮毁' => ' zhāo chéng mù huǐ', + '逐行扫描' => ' zhú háng sǎo miáo', + '金融杠杆' => ' jīn róng gàng gǎn', + '金帐汗国' => ' jīn zhàng hán guó', + '连锁反应' => ' lián suǒ fǎn yìng', + '酒精中毒' => ' jǐu jīng zhòng dú', + '精尽人亡' => ' jīng jìn rén wáng', + '游手好闲' => ' yóu shǒu hào xián', + '言为心声' => ' yán wéi xīn shēng', + '揎拳捋袖' => ' xuān quán luō xiù', + '网路应用' => ' wǎng lù yìng yòng', + '星移斗转' => ' xīng yí dǒu zhuǎn', + '侵权行为' => ' qīn quán xíng wéi', + '行政处罚' => ' xíng zhèng chǔ fá', + '斩将夺旗' => ' zhǎn jiàng duó qí', + '斩钉切铁' => ' zhǎn dīng qiē tiě', + '返还占有' => ' fǎn huán zhàn yǒu', + '压电效应' => ' yā diàn xiào yìng', + '金蝉脱壳' => ' jīn chán tuō qiào', + '轩轩甚得' => ' xuān xuān shèn dé', + '延颈跂踵' => ' yán jǐng qǐ zhǒng', + '来日方长' => ' lái rì fāng cháng', + '重新开始' => ' chóng xīn kāi shǐ', + '重新造林' => ' chóng xīn zào lín', + '使徒行传' => ' shǐ tú xíng zhuàn', + '重新统一' => ' chóng xīn tǒng yī', + '重新启动' => ' chóng xīn qǐ dòng', + '重修旧好' => ' chóng xiū jiù hǎo', + '压良为贱' => ' yā liáng wéi jiàn', + '璇霄丹阙' => ' xuán xiāo dān què', + '重新做人' => ' chóng xīn zuò rén', + '重整旗鼓' => ' chóng zhěng qí gǔ', + '经年累月' => ' jīng nián lěi yuè', + '乍暖还寒' => ' zhà nuǎn huán hán', + '细水长流' => ' xì shuǐ cháng liú', + '乡村音乐' => ' xiāng cūn yīn yuè', + '重庆大学' => ' chóng qìng dà xué', + '豁然贯通' => ' huò rán guàn tōng', + '斗量车载' => ' dǒu liáng chē zài', + '经济力量' => ' jīng jì lì liang', + '长绳系景' => ' cháng shéng xì jǐng', + '短中取长' => ' duǎn zhōng qǔ cháng', + '话长说短' => ' huà cháng shuō duǎn', + '生拉硬拽' => ' shēng lā yìng zhuài', + '深中肯綮' => ' shēn zhōng kěn qìng', + '坑绷拐骗' => ' kēng bēng guǎi piàn', + '质量效应' => ' zhì liàng xiào yìng', + '众星攒月' => ' zhòng xīng cuán yuè', + '冲动行为' => ' chōng dòng xíng wéi', + '神霄绛阙' => ' shén xiāo jiàng què', + '自坏长城' => ' zì huài cháng chéng', + '兢兢乾乾' => ' jīng jīng qián qián', + '外强中干' => ' wài qiáng zhōng gān', + '逞性妄为' => ' chěng xìng wàng wéi', + '参横斗转' => ' shēn héng dǒu zhuǎn', + '双重国籍' => ' shuāng chóng guó jí', + '双重人格' => ' shuāng chóng rén gé', + '成为笑柄' => ' chéng wéi xiào bǐng', + '转败为成' => ' zhuǎn bài wéi chéng', + '创巨痛深' => ' chuāng jù tòng shēn', + '纸短情长' => ' zhǐ duǎn qíng cháng', + '乘胜逐北' => ' chéng shèng zhú běi', + '下风方向' => ' xià fēng fāng xiàng', + '水穷山尽' => ' shuǐ qióng shān jìn', + '说短论长' => ' shuō duǎn lùn cháng', + '率由旧章' => ' shuài yóu jiù zhāng', + '少成若性' => ' shào chéng ruò xìng', + '长往远引' => ' cháng wǎng yuǎn yǐn', + '长线产品' => ' cháng xiàn chǎn pǐn', + '持枪抢劫' => ' chí qiāng qiāng jié', + '正中要害' => ' zhèng zhòng yào hài', + '沉着痛快' => ' chén zhuó tòng kuài', + '产生偏差' => ' chǎn shēng piān chā', + '众啄同音' => ' zhòng zhòu tóng yīn', + '侜张为幻' => ' zhōu zhāng wéi huàn', + '铢称寸量' => ' zhū chēng cùn liáng', + '鞭长驾远' => ' biān cháng jià yuǎn', + '重光累洽' => ' chóng guāng lèi qià', + '水尽山穷' => ' shuǐ jìn shān qióng', + '将门有将' => ' jiàng mén yǒu jiàng', + '源远流长' => ' yuán yuǎn liú cháng', + '霜行草宿' => ' shuāng xíng cǎo xiǔ', + '拽巷啰街' => ' zhuài xiàng luó jiē', + '正当防卫' => ' zhèng dàng fáng wèi', + '强颜欢笑' => ' qiǎng yán huān xiào', + '恒生银行' => ' héng shēng yín háng', + '说长道短' => ' shuō cháng dào duǎn', + '对证命名' => ' duì zhèng mìng míng', + '心手相应' => ' xīn shǒu xiāng yìng', + '旋转乾坤' => ' xuán zhuǎn qián kūn', + '兴师动众' => ' xīng shī dòng zhòng', + '双栖双宿' => ' shuāng qī shuāng sù', + '板上钉钉' => ' bǎn shàng dìng dīng', + '当轴处中' => ' dāng zhóu chǔ zhōng', + '官方网站' => ' guān fāng wǎng zhàn', + '史传小说' => ' shǐ zhuàn xiǎo shuō', + '说岳全传' => ' shuō yuè quán zhuàn', + '寸善片长' => ' cùn shàn piàn cháng', + '行险侥幸' => ' xíng xiǎn jiǎo xìng', + '量身定制' => ' liáng shēn dìng zhì', + '明窗净几' => ' míng chuāng jìng jī', + '长山山脉' => ' cháng shān shān mài', + '姓甚名谁' => ' xìng shèn míng shuí', + '龙荒蛮甸' => ' lóng huāng mán diàn', + '旧景重现' => ' jìu jǐng chóng xiàn', + '锥处囊中' => ' zhuī chǔ náng zhōng', + '草率收兵' => ' cǎo shuài shōu bīng', + '穷愁潦倒' => ' qióng chóu liáo dǎo', + '瞬态响应' => ' shùn tài xiǎng yìng', + '横抢硬夺' => ' hèng qiǎng yìng duó', + '洞中肯綮' => ' dòng zhōng kěn qìng', + '晃晃悠悠' => ' huàng huǎng yōu yōu', + '论长说短' => ' lùn cháng shuō duǎn', + '五行相生' => ' wǔ háng xiāng shēng', + '漂蓬断梗' => ' piāo péng duàn gěng', + '少年老成' => ' shào nián lǎo chéng', + '翩翩少年' => ' piān piān shào nián', + '汹涌澎湃' => ' xiōng yǒng péng pài', + '微创手术' => ' wēi chuāng shǒu shù', + '言归正传' => ' yán guī zhèng zhuàn', + '亲水长廊' => ' qīn shuǐ cháng láng', + '长生久视' => ' cháng shēng jiǔ shì', + '营养成分' => ' yíng yǎng chéng fèn', + '长江三峡' => ' cháng jiāng sān xiá', + '长话短说' => ' cháng huà duǎn shuō', + '嫌长道短' => ' xián cháng dào duǎn', + '说短道长' => ' shuō duǎn dào cháng', + '说长论短' => ' shuō cháng lùn duǎn', + '山穷水尽' => ' shān qióng shuǐ jìn', + '养虺成蛇' => ' yǎng huǐ chéng shé', + '长远目标' => ' cháng yuǎn mù biāo', + '浓抹淡妆' => ' nóng mò dàn zhuāng', + '斜行横阵' => ' xié xíng héng zhèn', + '迎接挑战' => ' yíng jiē tiǎo zhàn', + '化整为零' => ' huà zhěng wéi líng', + '不明真相' => ' bù míng zhēn xiàng', + '小时了了' => ' xiǎo shí liǎo liǎo', + '详星拜斗' => ' xiáng xīng bài dǒu', + '参回斗转' => ' shēn huí dǒu zhuǎn', + '多言数穷' => ' duō yán shuò qióng', + '雕肝琢肾' => ' diāo gān zhuó shèn', + '顺人应天' => ' shùn rén yìng tiān', + '适应环境' => ' shì yìng huán jìng', + '长命百岁' => ' cháng mìng bǎi suì', + '师直为壮' => ' shī zhí wéi zhuàng', + '长林丰草' => ' cháng lín fēng cǎo', + '博采众长' => ' bó cǎi zhòng cháng', + '钟鸣漏尽' => ' zhōng míng lòu jìn', + '弃短用长' => ' qì duǎn yòng cháng', + '扬长补短' => ' yáng cháng bǔ duǎn', + '十载寒窗' => ' shí zǎi hán chuāng', + '重温旧梦' => ' chóng wēn jiù mèng', + '蝉联冠军' => ' chán lián guàn jūn', + '赌长较短' => ' dǔ cháng jiào duǎn', + '长才广度' => ' cháng cái guǎng dù', + '重碳酸盐' => ' chóng tàn suān yán', + '蝉喘雷干' => ' chán chuǎn léi gān', + '昼短夜长' => ' zhòu duǎn yè cháng', + '测量元件' => ' cè liáng yuán jiàn', + '草率从事' => ' cǎo shuài cóng shì', + '悬石程书' => ' xuán dàn chéng shū', + '浓妆淡抹' => ' nóng zhuāng dàn mò', + '重碳酸钙' => ' chóng tàn suān gài', + '虚晃一枪' => ' xiù huàng yī qiāng', + '手足重茧' => ' shǒu zú chóng jiǎn', + '长年累月' => ' cháng nián lěi yuè', + '晨昏定省' => ' chén hūn dìng xǐng', + '深山长谷' => ' shēn shān cháng gǔ', + '昏定晨省' => ' hūn dìng chén xǐng', + '强迫观念' => ' qiǎng pò guān niàn', + '长岛冰茶' => ' cháng dǎo bīng chá', + '深仇宿怨' => ' shēn chóu xiǔ yuàn', + '鉴真和尚' => ' jiàn zhēn hé shang', + '中坚力量' => ' zhōng jiān lì liang', + '书归正传' => ' shū guī zhèng zhuàn', + '整躬率物' => ' zhěng gōng shuài wù', + '振兴中华' => ' zhèn xīng zhōng huá', + '校短推长' => ' xiào duǎn tuī cháng', + '沉着应战' => ' chén zhuó yìng zhàn', + '首尾相应' => ' shǒu wěi xiāng yìng', + '长篇连载' => ' cháng piān lián zǎi', + '阆苑琼楼' => ' làng yuàn qióng lóu', + '还乡昼锦' => ' huán xiāng zhòu jǐn', + '昏镜重明' => ' hūn jìng chóng míng', + '重峦复嶂' => ' chóng luán fù zhàng', + '长算远略' => ' cháng suàn yuǎn lüè', + '水中著盐' => ' shuǐ zhōng zhuó yán', + '秤斤注两' => ' chēng jīn zhù liǎng', + '火耕水种' => ' huǒ gēng shuǐ zhòng', + '山长水阔' => ' shān cháng shuǐ kuò', + '水中捉月' => ' shui zhong zhuo yue', + '说长话短' => ' shuō cháng huà duǎn', + '山阴乘兴' => ' shān yīn chéng xīng', + '长春新碱' => ' cháng chūn xīn jiǎn', + '重建家园' => ' chóng jiàn jiā yuán', + '遁世长往' => ' dùn shì cháng wǎng', + '解弦更张' => ' jiě xián gēng zhāng', + '水宿山行' => ' shuǐ xiǔ shān xíng', + '相去甚远' => ' xiāng qù shèn yuǎn', + '日月重光' => ' rì yuè chóng guāng', + '逼良为娼' => ' bī liáng wéi chāng', + '事实真相' => ' shì shí zhēn xiàng', + '进行性交' => ' jìn xíng xìng jiāo', + '钻坚仰高' => ' zuàn jiān yǎng gāo', + '膀胱结石' => ' páng guāng jié shí', + '政治斗争' => ' zhèng zhì dòu zhēng', + '推广应用' => ' tuī guǎng yìng yòng', + '窗明几净' => ' chuāng míng jī jìng', + '使羊将狼' => ' shǐ yáng jiàng láng', + '正中己怀' => ' zhèng zhòng jǐ huái', + '长颈鸟喙' => ' cháng jǐng niǎo huì', + '困难重重' => ' kùn nán chóng chóng', + '应用程式' => ' yìng yòng chéng shì', + '朝阳鸣凤' => ' zhāo yáng míng fèng', + '中央银行' => ' zhōng yāng yín háng', + '应用软件' => ' yìng yòng ruǎn jiàn', + '改弦更张' => ' gǎi xián gēng zhāng', + '彰明较著' => ' zhāng míng jiào zhù', + '重新评价' => ' chóng xīn píng jià', + '重生爷娘' => ' chóng shēng yé niáng', + '广文先生' => ' guǎng wén xiān sheng', + '光电效应' => ' guāng diàn xiào yìng', + '调神畅情' => ' tiáo shén chàng qíng', + '正身率下' => ' zhèng shēn shuài xià', + '山崩钟应' => ' shān bēng zhōng yìng', + '调停两用' => ' tiáo tíng liǎng yòng', + '争短论长' => ' zhēng duǎn lùn cháng', + '穷形尽相' => ' qióng xíng jìn xiàng', + '抢风航行' => ' qiāng fēng háng xíng', + '圣经外传' => ' shèng jīng wài zhuàn', + '重新调整' => ' chóng xīn tiáo zhěng', + '公共行政' => ' gōng gòng xíng zhèng', + '算命先生' => ' suàn mìng xiān sheng', + '笑脸相迎' => ' xiào liǎn xiàng yíng', + '横行直撞' => ' héng xíng zhí zhuàng', + '穿着讲究' => ' chuān zhuó jiǎng jiu', + '王侯将相' => ' wáng hóu jiàng xiàng', + '逞娇呈美' => ' chěng jiāo chéng měi', + '蒙头转向' => ' mēng tóu zhuàn xiàng', + '青灯黄卷' => ' qīng dēng huáng juàn', + '堂皇冠冕' => ' táng huáng guàn miǎn', + '率尔成章' => ' shuài ěr chéng zhāng', + '重新装修' => ' chóng xīn zhuāng xīu', + '庄严宝相' => ' zhuāng yán bǎo xiàng', + '唱筹量沙' => ' chàng chóu liáng shā', + '胸中万卷' => ' xiōng zhōng wàn juàn', + '兴衰成败' => ' xīng shuāi chéng bài', + '盛衰兴废' => ' shèng shuāi xīng fèi', + '萍飘蓬转' => ' píng piāo péng zhuàn', + '双足重茧' => ' shuāng zú chóng jiǎn', + '长盛不衰' => ' cháng shèng bù shuāi', + '长亭短亭' => ' cháng tíng duǎn tíng', + '争长论短' => ' zhēng cháng lùn duǎn', + '赤诚相见' => ' chì chéng xiàng jiàn', + '兵多将广' => ' bīng duō jiàng guǎng', + '黄卷青灯' => ' huáng juàn qīng dēng', + '道长争短' => ' dào cháng zhēng duǎn', + '防火长城' => ' fáng huǒ cháng chéng', + '承平盛世' => ' chéng píng shèng shì', + '黄钟长弃' => ' huáng zhōng cháng qì', + '转轮圣王' => ' zhuàn lún shèng wáng', + '甚嚣尘上' => ' shèn xiāo chén shàng', + '壮发冲冠' => ' zhuàng fā chōng guàn', + '圣君贤相' => ' shèng jīng xián xiàng', + '拳脚相向' => ' quán jiǎo xiāng xiàng', + '长江天堑' => ' cháng jiāng tiān qiàn', + '条条框框' => ' tiáo tiáo kuàng kuàng', + '正邪相争' => ' zhèng xié xiāng zhēng', + '勉勉强强' => ' miǎn miǎn qiǎng qiáng', + '同声相应' => ' tóng shēng xiāng yìng', + '争强好胜' => ' zhēng qiáng hào shèng', + '争长竞短' => ' zhēng cháng jìng duǎn', + '逞强好胜' => ' chěng qiáng hào shèng', + '山中宰相' => ' shān zhōng zǎi xiàng', + '圣经贤传' => ' shèng jīng xián zhuàn', + '精兵强将' => ' jīng bīng qiáng jiàng', + '校短量长' => ' jiào duǎn liáng cháng', + '账房先生' => ' zhàng fáng xiān sheng', + '归心似箭' => ' guī xīn sì jiàn', + '短中抽长' => ' duǎn zhōng chōu cháng', + '长长短短' => ' cháng cháng duǎn duǎn', + '竞短争长' => ' jìng duǎn zhēng cháng', + '中山狼传' => ' zhōng shān láng zhuàn', + '上当受骗' => ' shàng dàng shòu piàn', + '生肖属相' => ' shēng xiào shǔ xiàng', + '长城饭店' => ' cháng chéng fàn diàn', + '蒸气重整' => ' zhēng qì chóng zhěng', + '遣兵调将' => ' qiǎn bīng diào jiàng', + '山长水远' => ' shān cháng shuǐ yuǎn', + '三长两短' => ' sān cháng liǎng duǎn', + '车载船装' => ' chē zǎi chuán zhuāng', + '铢两相称' => ' zhū liǎng xiāng chèn', + '更长梦短' => ' gēng cháng mèng duǎn', + '着手成春' => ' zhuó shǒu chéng chūn', + '项背相望' => ' xiàng bèi xiāng wàng', + '朝鲜战争' => ' cháo xiǎn zhàn zhēng', + '敩学相长' => ' zuàn xué xiāng cháng', + '长篇小说' => ' cháng piān xiǎo shuō', + '善善从长' => ' shàn shàn cóng cháng', + '乘风兴浪' => ' chéng fēng xīng làng', + '扇枕温被' => ' shān zhěn wēn chuáng', + '说长说短' => ' shuō cháng shuō duǎn', + '长荣航空' => ' cháng róng háng kōng', + '九转功成' => ' jiǔ zhuàn gōng chéng', + '正中下怀' => ' zhèng zhòng xià huái', + '调兵遣将' => ' diào bīng qiǎn jiàng', + '天兵天将' => ' tiān bīng tiān jiàng', + '丧尽天良' => ' sàng jìn tiān liáng', + '一长两短' => ' yī cháng liǎng duǎn', + '电动转盘' => ' diàn dòng zhuàn pán', + '寸长片善' => ' cùn cháng piàn shàn', + '发上冲冠' => ' fà shàng chōng guān', + '较长絜短' => ' jiào cháng xié duǎn', + '彰明昭着' => ' zhāng míng zhāo zhe', + '长虺成蛇' => ' zhǎng huǐ chéng shé', + '洋为中用' => ' yáng wéi zhōng yòng', + '浩浩汤汤' => ' hào hào shāng shāng', + '寸量铢称' => ' cùn liáng zhū chēng', + '山峦重叠' => ' shān luán chóng dié', + '乘胜追击' => ' chéng shèng zhuī jī', + '过关斩将' => ' guò guān zhǎn jiàng', + '还魂橡胶' => ' huán hún xiàng jiāo', + '传为笑柄' => ' chuán wéi xiào bǐng', + '连中三元' => ' lián zhòng sān yuán', + '彰明昭著' => ' zhāng míng zhāo zhù', + '多口相声' => ' duō kǒu xiàng sheng', + '雀屏中选' => ' què píng zhòng xuǎn', + '单口相声' => ' dān kǒu xiàng sheng', + '相切相磋' => ' xiāng qiē xiāng cuō', + '公共零点' => ' gōng gòng líng diǎn', + '降妖捉怪' => ' xiáng yāo zhuō guài', + '山高水长' => ' shān gāo shuǐ cháng', + '干城之将' => ' gān chéng zhī jiàng', + '工商银行' => ' gōng shāng yín háng', + '心长绠短' => ' xīn cháng gěng duǎn', + '梦想颠倒' => ' mèng xiǎng diān dǎo', + '心事重重' => ' xīn shì chóng chóng', + '面折庭争' => ' miàn shé tíng zhēng', + '凤鸣朝阳' => ' fèng míng zhāo yáng', + '顶踵尽捐' => ' dǐng zhǒng jìn juān', + '膏粱年少' => ' gāo liáng nián shào', + '交响乐团' => ' jiāo xiǎng yuè tuán', + '香花供养' => ' xiāng huā gòng yǎng', + '东方将白' => ' dong fang jiang bai', + '鸣凤朝阳' => ' míng fèng zhāo yáng', + '长平之战' => ' cháng píng zhī zhàn', + '宏观调控' => ' hóng guān tiáo kòng', + '相貌堂堂' => ' xiàng mào táng táng', + '相门有相' => ' xiàng mén yǒu xiàng', + '东窗消息' => ' dōng chuāng xiāo xi', + '仰天长叹' => ' yǎng tiān cháng tàn', + '轰动效应' => ' hōng dòng xiào yìng', + '兴兵动众' => ' xīng bīng dòng zhòng', + '滚滚长江' => ' gǔn gǔn cháng jiāng', + '反正还淳' => ' fǎn zhèng huán chún', + '运动健将' => ' yùn dòng jiàn jiàng', + '羊瘙痒症' => ' yáng sào yǎng zhèng', + '旋乾转坤' => ' xuán qián zhuǎn kūn', + '响应时间' => ' xiǎng yìng shí jiān', + '正宫娘娘' => ' zhēng gōng niáng niáng', + '受到影响' => ' shòu dào yǐng xiǎng', + '晕头转向' => ' yūn tóu zhuàn xiàng', + '造谣中伤' => ' zào yáo zhòng shāng', + '方领圆冠' => ' fāng lǐng yuán guàn', + '斗转参横' => ' dǒu zhuǎn shēn héng', + '缅甸联邦' => ' miǎn diàn lián bāng', + '作善降祥' => ' zuò shàn jiàng xiáng', + '长街短巷' => ' cháng jiē duǎn xiàng', + '重峦叠嶂' => ' chóng luán dié zhàng', + '转轮手枪' => ' zhuàn lún shǒu qiāng', + '水远山长' => ' shuǐ yuǎn shān cháng', + '仰天长啸' => ' yǎng tiān cháng xiào', + '广种薄收' => ' guǎng zhòng bó shōu', + '广为流传' => ' guǎng wéi liú chuán', + '康乾盛世' => ' kāng qián shèng shì', + '公共交通' => ' gōng gòng jiāo tōng', + '公共卫生' => ' gōng gòng wèi shēng', + '传风扇火' => ' chuán fēng shān huǒ', + '衡短论长' => ' héng duǎn lùn cháng', + '楞手楞脚' => ' lèng shǒu lèng jiǎo', + '应天承运' => ' yìng tiān chéng yùn', + '笼鸟槛猿' => ' lóng niǎo jiàn yuán', + '公共场所' => ' gōng gòng chǎng suǒ', + '摇摇晃晃' => ' yáo yáo huàng huàng', + '转败为胜' => ' zhuǎn bài wéi shèng', + '沸沸汤汤' => ' fèi fèi shāng shāng', + '跌跌跄跄' => ' diē diē qiàng qiàng', + '较短絜长' => ' jiào duǎn xié cháng', + '情长纸短' => ' qíng cháng zhǐ duǎn', + '对口相声' => ' duì kǒu xiàng sheng', + '青春年少' => ' qīng chūn nián shào', + '学有专长' => ' xué yǒu zhuān cháng', + '远涉重洋' => ' yuǎn shè chóng yáng', + '从长商议' => ' cóng cháng shāng yì', + '弹冠相庆' => ' tán guān xiāng qìng', + '长安少年' => ' cháng ān shào nián', + '斗升之水' => ' dǒu shēng zhī shuǐ', + '虱处裈中' => ' shī chǔ kūn zhōng', + '将遇良才' => ' jiàng yù liáng cái', + '鉴影度形' => ' jiàn yǐng duó xíng', + '将功折过' => ' jiāng gōng shé guò', + '残兵败将' => ' cán bīng bài jiàng', + '拽象拖犀' => ' zhuài xiàng tuō xī', + '转败为功' => ' zhuǎn bài wéi gōng', + '氧炔吹管' => ' yǎng quē chuī guǎn', + '惊起梁尘' => ' jīng qǐ liáng chén', + '静电感应' => ' jìng diàn gǎn yìng', + '进贤兴功' => ' jìn xián xīng gōng', + '满口应承' => ' mǎn kǒu yìng chéng', + '气贯长虹' => ' qì guàn cháng hóng', + '着人先鞭' => ' zhuó rén xiān biān', + '进退消长' => ' jìn tuì xiāo cháng', + '将相之器' => ' jiàng xiàng zhī qì', + '交响乐队' => ' jiāo xiǎng yuè duì', + '确定效应' => ' què dìng xiào yìng', + '神成为人' => ' shén chéng wéi rén', + '哗众取宠' => ' huá zhòng qǔ chǒng', + '见性成佛' => ' jiàn xìng chéng fó', + '嚼齿穿龈' => ' jiáo chǐ chuān yín', + '鸾颠凤倒' => ' luán diān fèng dǎo', + '清史列传' => ' qīng shǐ liè zhuàn', + '开疆拓境' => ' kāi jiāng tuò jìng', + '亢音高唱' => ' gāng yīn gāo chàng', + '不见经传' => ' bù jiàn jīng zhuàn', + '简切了当' => ' jiǎn qiè liǎo dàng', + '天旋地转' => ' tiān xuán dì zhuàn', + '水浒全传' => ' shuǐ hǔ quán zhuàn', + '嚼穿龈血' => ' jiáo chuān yín xuè', + '清风劲节' => ' qīng fēng jìng jié', + '永贞内禅' => ' yǒng zhēn nèi shàn', + '间见层出' => ' jiàn xiàn céng chū', + '较短比长' => ' jiào duǎn bǐ cháng', + '沅江九肋' => ' yuán jiāng jiǔ lèi', + '嚼腭搥床' => ' jiáo è chuí chuáng', + '嘴快舌长' => ' zuǐ kuài shé cháng', + '阶跃响应' => ' jiē yuè xiǎng yìng', + '作浪兴风' => ' zuò làng xīng fēng', + '法轮常转' => ' fǎ lún cháng zhuàn', + '江郎才尽' => ' jiāng láng cái jìn', + '兴风作浪' => ' xīng fēng zuò làng', + '少先队员' => ' shào xiān duì yuán', + '知疼着痒' => ' zhī téng zháo yǎng', + '专家评价' => ' zhuān jiā píng jià', + '更型换代' => ' gēng xíng huàn dài', + '少管闲事' => ' shào guǎn xián shì', + '论短道长' => ' lùn duǎn dào cháng', + '尝尽心酸' => ' cháng jìn xīn suān', + '乱箭攒心' => ' luàn jiàn cuán xīn', + '旧调重弹' => ' jiù diào chóng tán', + '应用卫星' => ' yìng yòng wèi xīng', + '贞松劲柏' => ' zhēn sōng jìng bǎi', + '羊瘙痒病' => ' yáng sào yǎng bìng', + '了若指掌' => ' liǎo ruò zhǐ zhǎng', + '条件反应' => ' tiáo jiàn fǎn yìng', + '管弦乐团' => ' guǎn xián yuè tuán', + '朝梁暮陈' => ' zhāo liáng mù chén', + '朝梁暮周' => ' zhāo liáng mù zhōu', + '横行天下' => ' héng xíng tiān xià', + '空中少爷' => ' kōng zhōng shào ye', + '简单明了' => ' jiǎn dān míng liǎo', + '中国银行' => ' zhōng guó yín háng', + '应用程序' => ' yìng yòng chéng xù', + '应天顺人' => ' yìng tiān shùn rén', + '语长心重' => ' yǔ cháng xīn zhòng', + '鼋鸣鳖应' => ' yuán míng biē yìng', + '漏尽钟鸣' => ' lòu jìn zhōng míng', + '语短情长' => ' yǔ duǎn qíng cháng', + '拱手而降' => ' gǒng shòu ér xiáng', + '臭名昭著' => ' chòu míng zhāo zhù', + '对称空间' => ' duì chèn kōng jiān', + '聪明绝顶' => ' cōng ming jué dǐng', + '联调联试' => ' lián tiáo lián shì', + '惯用伎俩' => ' guàn yòng jì liǎng', + '广东音乐' => ' guǎng dōng yīn yuè', + '应天顺民' => ' yìng tiān shùn mín', + '广陵散绝' => ' guǎng líng sǎn jué', + '遇难成祥' => ' yù nàn chéng xiáng', + '岳镇渊渟' => ' yuè zhèn yuān tīng', + '有效成分' => ' yǒu xiào chéng fèn', + '交通银行' => ' jiāo tōng yín háng', + '万里长江' => ' wàn lǐ cháng jiāng', + '梗泛萍漂' => ' gěng fàn píng piāo', + '万里长城' => ' wàn lǐ cháng chéng', + '更令明号' => ' gēng lìng míng hào', + '子孙娘娘' => ' zǐ sūn niáng niang', + '毁冠裂裳' => ' huǐ guān liè cháng', + '横征苛敛' => ' hèng zhēng kē liǎn', + '词长效应' => ' cí cháng xiào yìng', + '名声籍甚' => ' míng shēng jí shèn', + '封豕长蛇' => ' fēng shǐ cháng shé', + '语重心长' => ' yǔ zhòng xīn cháng', + '灭景追风' => ' miè yǐng zhuī fēng', + '常年累月' => ' cháng nián lěi yuè', + '风尘肮脏' => ' fēng chén āng zāng', + '丰草长林' => ' fēng cǎo cháng lín', + '月亮女神' => ' yuè liang nǔ: shén', + '以升量石' => ' yǐ shēng liáng dàn', + '望子成龙' => ' wàng zǐ chéng lóng', + '槁项黄馘' => ' gǎo xiàng huáng xù', + '讯框中继' => ' xùn kuàng zhōng jì', + '粉妆玉琢' => ' fěn zhuāng yù zhuó', + '饮马长江' => ' yǐn mǎ cháng jiāng', + '飞流短长' => ' fēi liú duǎn cháng', + '改姓更名' => ' gǎi xìng gēng míng', + '粘胶纤维' => ' nián jiāo xiān wéi', + '更深人静' => ' gēng shēn rén jìng', + '装模作样' => ' zhuāng mú zuò yàng', + '望洋兴叹' => ' wàng yáng xīng tàn', + '发踊冲冠' => ' fà yǒng chōng guān', + '阴凝坚冰' => ' yīn níng jiān bīng', + '山公倒载' => ' shān gōng dǎo zǎi', + '多难兴邦' => ' duō nàn xīng bāng', + '豆重榆瞑' => ' dòu chóng yú míng', + '乜斜缠帐' => ' niè xié chán zhàng', + '藤野先生' => ' téng yě xiān sheng', + '孽障种子' => ' niè zhàng zhǒng zǐ', + '蒸发空调' => ' zhēng fā kōng tiáo', + '恩甚怨生' => ' ēn shèn yuàn shēng', + '转变抹角' => ' zhuǎn biàn mò jiǎo', + '明白了当' => ' míng bái liǎo dàng', + '藏传佛教' => ' zàng chuán fó jiào', + '告老还乡' => ' gào lǎo huán xiāng', + '藏茴香果' => ' zàng huí xiāng guǒ', + '袅娜娉婷' => ' niǎo nuó pīng tíng', + '转来转去' => ' zhuàn lái zhuàn qù', + '夜长梦短' => ' yè cháng mèng duǎn', + '商业应用' => ' shāng yè yìng yòng', + '捻捻转儿' => ' niǎn niǎn zhuàn ér', + '说来话长' => ' shuō lái huà cháng', + '借面吊丧' => ' jiè miàn diào sāng', + '更高性能' => ' gēng gāo xìng néng', + '扛鼎抃牛' => ' gāng dǐng biàn niú', + '钧天广乐' => ' jūn tiān guǎng yuè', + '生意兴隆' => ' shēng yì xīng lóng', + '拘神遣将' => ' jū shén qiǎn jiàng', + '率兽食人' => ' shuài shòu shí rén', + '正义斗争' => ' zhèng yì dòu zhēng', + '简截了当' => ' jiǎn jié liǎo dàng', + '旧梦重温' => ' jiù mèng chóng wēn', + '产前检查' => ' chǎn qián jiǎn chá', + '钟鼎人家' => ' zhōng dǐng rén jia', + '矿物成分' => ' kuàng wù chéng fèn', + '众好众恶' => ' zhòng hào zhòng wù', + '旷日长久' => ' kuàng rì cháng jiǔ', + '破镜重圆' => ' pò jìng chóng yuán', + '化零为整' => ' huà líng wéi zhěng', + '子癫前症' => ' zǐ diān qián zhèng', + '睡眠失调' => ' shuì mián shī tiáo', + '睡回笼觉' => ' shuì huí lóng jiào', + '盈箱累箧' => ' yíng xiāng lěi qiè', + '黄发垂髫' => ' huáng fà chuí tiáo', + '妙语横生' => ' miào yǔ hèng shēng', + '倦鸟知还' => ' juàn niǎo zhī huán', + '反戈相向' => ' fǎn gē xiāng xiàng', + '商人银行' => ' shāng rén yín háng', + '贫穷潦倒' => ' pín qíong liáo dǎo', + '繁荣兴旺' => ' fán róng xīng wàng', + '差分方程' => ' chā fēn fāng chéng', + '变徵之声' => ' biàn zhǐ zhī shēng', + '论长道短' => ' lùn cháng dào duǎn', + '膏场绣浍' => ' gāo cháng xiù kuài', + '蜚短流长' => ' fēi duǎn liú cháng', + '虾兵蟹将' => ' xiā bīng xiè jiàng', + '方寸万重' => ' fāng cùn wàn chóng', + '昼长夜短' => ' zhòu cháng yè duǎn', + '干劲冲天' => ' gān jìn chōng tiān', + '朝鲜太宗' => ' cháo xiǎn tài zōng', + '长鸣都尉' => ' cháng míng dōu wèi', + '敛声屏气' => ' liǎn shēng bǐng qì', + '应付账款' => ' yìng fù zhàng kuǎn', + '众口难调' => ' zhòng kǒu nán tiáo', + '众毛攒裘' => ' zhòng máo cuán qiú', + '大中学生' => ' dà zhōng xué sheng', + '种植园主' => ' zhòng zhí yuán zhǔ', + '中信银行' => ' zhōng xìn yín háng', + '学生运动' => ' xué sheng yùn dòng', + '数短论长' => ' shǔ duǎn lùn cháng', + '攒零合整' => ' cuán líng hé zhěng', + '掸邦高原' => ' shàn bāng gāo yuán', + '出将入相' => ' chū jiàng rù xiàng', + '撩是生非' => ' liáo shì shēng fēi', + '败将残兵' => ' bài jiàng cán bīng', + '颠鸾倒凤' => ' diān luán dǎo fèng', + '王贡弹冠' => ' wáng gòng dàn guàn', + '挑唇料嘴' => ' tiǎo chún liào zuǐ', + '清都绛阙' => ' qīng dōu jiàng què', + '从容应对' => ' cóng róng yìng duì', + '全息照相' => ' quán xī zhào xiàng', + '青藏高原' => ' qīng zàng gāo yuán', + '调唇弄舌' => ' tiáo chún nòng shé', + '调风弄月' => ' tiáo fēng nòng yuè', + '软件调试' => ' ruǎn jiàn tiáo shì', + '从长计较' => ' cóng cháng jì jiào', + '扬长避短' => ' yáng cháng bì duǎn', + '调良稳泛' => ' tiáo liáng wěn fàn', + '拔刀相向' => ' bá dāo xiāng xiàng', + '人丁兴旺' => ' rén dīng xīng wàng', + '全能冠军' => ' quán néng guàn jūn', + '成年累月' => ' chéng nián lěi yuè', + '揣合逢迎' => ' chuǎi hé féng yíng', + '重山复水' => ' chóng shān fù shuǐ', + '铜盘重肉' => ' tóng pán zhòng ròu', + '万里长征' => ' wàn lǐ cháng zhēng', + '川渟岳峙' => ' chuān tīng yuè zhì', + '传授知识' => ' chuán shòu zhī shi', + '穿红着绿' => ' chuān hóng zhuó lǜ', + '重熙累盛' => ' chóng xī lěi shèng', + '飞短流长' => ' fēi duǎn liú cháng', + '忘啜废枕' => ' wàng chuò fèi zhěn', + '公共财产' => ' gōng gòng cái chǎn', + '黄花姑娘' => ' huáng huā gū niang', + '餐桌转盘' => ' cān zhuō zhuàn pán', + '应召女郎' => ' yìng zhào nǔ: láng', + '重裀列鼎' => ' chóng yīn liè dǐng', + '鹰击长空' => ' yīng jī cháng kōng', + '鸟尽弓藏' => ' niǎo jìn gōng cáng', + '应天顺时' => ' yìng tiān shùn shí', + '应用平台' => ' yìng yòng píng tái', + '感应线圈' => ' gǎn yìng xiàn quān', + '危机重重' => ' wēi jī chóng chóng', + '重山复岭' => ' chóng shān fù lǐng', + '长材小试' => ' cháng cái xiǎo shì', + '量子场论' => ' liàng zǐ chǎng lùn', + '率以为常' => ' shuài yǐ wéi cháng', + '剪切形变' => ' jiǎn qiē xíng biàn', + '剂量效应' => ' jì liàng xiào yìng', + '承销价差' => ' chéng xiāo jià chā', + '远渡重洋' => ' yuǎn dù chóng yáng', + '保长对应' => ' bǎo cháng duì yìng', + '对称中心' => ' duì chèn zhōng xīn', + '彷徨失措' => ' páng huáng shī cuò', + '炮凤烹龙' => ' páo fèng pēng lóng', + '重新审视' => ' chóng xīn shěn shì', + '手下败将' => ' shǒu xià bài jiàng', + '前缘未了' => ' qián yuán wèi liǎo', + '旁通曲畅' => ' páng tōng qǔ chàng', + '雕章琢句' => ' diāo zhāng zhuó jù', + '烹龙炮凤' => ' pēng lóng páo fèng', + '断还归宗' => ' duàn huán guī zōng', + '长安道上' => ' cháng ān dào shàng', + '娉婷袅娜' => ' pīng tíng niǎo nuó', + '长蛇封豕' => ' cháng shé fēng shǐ', + '为好成歉' => ' wéi hǎo chéng qiàn', + '传为笑谈' => ' chuán wéi xiào tán', + '刀耕火种' => ' dāo gēng huǒ zhòng', + '调舌弄唇' => ' tiáo shé nòng chún', + '援交小姐' => ' yuán jiāo xiǎo jie', + '顺应不良' => ' shùn yìng bù liáng', + '顺应天时' => ' shùn yìng tiān shí', + '颂声载道' => ' sòng shēng zǎi dào', + '穷困潦倒' => ' qióng kùn liáo dǎo', + '往渚还汀' => ' wǎng zhǔ huán tīng', + '穷年累世' => ' qióng nián lěi shì', + '洞鉴废兴' => ' dòng jiàn fèi xīng', + '穷年累月' => ' qióng nián lěi yuè', + '枉口诳舌' => ' wǎng kǒu kuáng shé', + '床头金尽' => ' chuáng tóu jīn jìn', + '兵微将寡' => ' bīng wēi jiàng guǎ', + '成败兴废' => ' chéng bài xīng fèi', + '春秋三传' => ' chūn qīu sān zhuàn', + '率土同庆' => ' shuài tǔ tóng qìng', + '弹性形变' => ' tán xìng xíng biàn', + '重见天日' => ' chóng jiàn tiān rì', + '戎事倥偬' => ' róng shì kǒng zǒng', + '憨豆先生' => ' hān dòu xiān sheng', + '报应不爽' => ' bào yìng bù shuǎng', + '强死强活' => ' qiǎng sǐ qiǎng huó', + '弓长岭区' => ' gōng cháng lǐng qū', + '万象更新' => ' wàn xiàng gēng xīn', + '傀儡政权' => ' kuǐ lěi zhèng quán', + '强的松龙' => ' qiáng dí sōng lóng', + '陪唱小姐' => ' péi chàng xiǎo jie', + '强弓劲弩' => ' qiáng gōng jìng nǔ', + '天宝当年' => ' tian bao dang nian', + '抢劫银行' => ' qiǎng jié yín háng', + '百舍重趼' => ' bǎi shè chóng jiǎn', + '连蒙带骗' => ' lián mēng dài piàn', + '三旨相公' => ' sān zhǐ xiàng gōng', + '淡妆轻抹' => ' dàn zhuāng qīng mò', + '云窗雾槛' => ' yún chuāng wù jiàn', + '道长论短' => ' dào cháng lùn duǎn', + '电光朝露' => ' diàn guāng zhāo lù', + '代为说项' => ' dài wéi shuō xiàng', + '翘首引领' => ' qiáo shǒu yǐn lǐng', + '持人长短' => ' chí rén cháng duǎn', + '扭转乾坤' => ' niǔ zhuǎn qián kūn', + '黑白相间' => ' hēi bái xiāng jiàn', + '电子工程' => ' diàn zǐ gōng chéng', + '网络应用' => ' wǎng luò yìng yòng', + '福寿绵长' => ' fú shòu mián cháng', + '朗朗乾坤' => ' lǎng lǎng qián kūn', + '泪干肠断' => ' lèi gān cháng duàn', + '佹形僪状' => ' guǐ xíng yù zhuàng', + '中兴新村' => ' zhōng xīng xīn cūn', + '中规中矩' => ' zhòng guī zhòng jǔ', + '织田信长' => ' zhī tián xìn cháng', + '过分强调' => ' guò fèn qiáng diào', + '粮尽援绝' => ' liáng jìn yuán jué', + '朝成暮遍' => ' zhāo chéng mù biàn', + '海水难量' => ' hǎi shuǐ nán liáng', + '九九重阳' => ' jǐu jǐu chóng yáng', + '牛头刨床' => ' niú tóu bào chuáng', + '梁上君子' => ' liáng shàng jūn zǐ', + '斩将搴旗' => ' zhǎn jiàng qiān qí', + '久别重逢' => ' jiǔ bié chóng féng', + '连街倒巷' => ' lián jiē dǎo xiàng', + '张脉偾兴' => ' zhāng mài fèn xīng', + '精灵宝钻' => ' jīng líng bǎo zuàn', + '切中时病' => ' qiè zhòng shí bìng', + '电子手帐' => ' diàn zǐ shǒu zhàng', + '两样东西' => ' liǎng yàng dōng xi', + '五言长城' => ' wǔ yán cháng chéng', + '登台拜将' => ' dēng tái bài jiàng', + '千了百当' => ' qiān liǎo bǎi dàng', + '长生不老' => ' cháng shēng bù lǎo', + '上好下甚' => ' shàng hǎo xià shèn', + '长生禄位' => ' cháng shēng lù wèi', + '山溜穿石' => ' shān liù chuān shí', + '搴旗斩将' => ' qiān qí zhǎn jiàng', + '倒箧倾筐' => ' dǎo qiè qīng kuāng', + '千乘之国' => ' qiān shèng zhī guó', + '长江流域' => ' cháng jiāng líu yù', + '长风破浪' => ' cháng fēng pò làng', + '吃亏上当' => ' chī kuī shàng dàng', + '倒凤颠鸾' => ' dǎo fèng diān luán', + '间谍软件' => ' jiàn dié ruǎn jiàn', + '夏虫朝菌' => ' xià chóng zhāo jūn', + '超超玄著' => ' chāo chāo xuán zhù', + '拜将封侯' => ' bài jiàng fēng hóu', + '拣佛烧香' => ' jiǎn fó shāo xiāng', + '强词夺正' => ' qiǎng cí duó zhèng', + '成都平原' => ' chéng dū píng yuán', + '问长问短' => ' wèn cháng wèn duǎn', + '损兵折将' => ' sǔn bīng zhé jiàng', + '唯唯连声' => ' wěi wěi lián shēng', + '村生泊长' => ' cūn shēng bó cháng', + '百舍重茧' => ' bǎi shè chóng jiǎn', + '百了千当' => ' bǎi liǎo qiān dāng', + '旦种暮成' => ' dàn zhòng mù chéng', + '寸长尺短' => ' cùn cháng chǐ duǎn', + '倒裳索领' => ' dào cháng suǒ lǐng', + '秤平斗满' => ' chèng píng dǒu mǎn', + '升斗小民' => ' shēng dǒu xiǎo mín', + '登坛拜将' => ' dēng tán bài jiàng', + '标准偏差' => ' biāo zhǔn piān chā', + '帝王将相' => ' dì wáng jiàng xiàng', + '相得甚欢' => ' xiāng dé shèn huān', + '想出风头' => ' xiǎng chū fēng tou', + '长柄勺子' => ' cháng bǐng sháo zi', + '表里相应' => ' biǎo lǐ xiāng yìng', + '长荣海运' => ' cháng róng hǎi yùn', + '从严惩处' => ' cóng yán chéng chǔ', + '同侪审查' => ' tóng chái shěn chá', + '更姓改物' => ' gēng xìng gǎi wù', + '重关击柝' => ' chóng guān jī tuò', + '荷枪实弹' => ' hè qiāng shí dàn', + '朝种暮获' => ' zhāo zhǒng mù hù', + '扣壶长吟' => ' kòu hú cháng yín', + '一针见血' => ' yī zhēn jiàn xiě', + '率土之滨' => ' shuài tǔ zhī bīn', + '枕席还师' => ' zhěn xí huán shī', + '三占从二' => ' sān zhān cóng èr', + '世界银行' => ' shì jiè yín háng', + '朝奏夕召' => ' zhāo zòu xī zhào', + '朝奏暮召' => ' zhāo zòu mù zhào', + '率由旧则' => ' shuài yóu jiù zé', + '子宫后倾' => ' zǐ gōng hòu qīng', + '置之脑后' => ' zhì zhī nǎo hòu', + '朝钟暮鼓' => ' zhāo zhōng mù gǔ', + '子宫脱垂' => ' zǐ gōng tuō chuí', + '会计人员' => ' kuài jì rén yuán', + '正冠纳履' => ' zhèng guàn nà lǚ', + '抒情散文' => ' shū qíng sǎn wén', + '大肠杆菌' => ' dà cháng gǎn jūn', + '知人善任' => ' zhī rén shàn rèn', + '看家本领' => ' kān jiā běn lǐng', + '书缺有间' => ' shū quē yǒu jiàn', + '会计报表' => ' kuài jì bào biǎo', + '束缊请火' => ' shù yùn qǐng huǒ', + '人造草坪' => ' rén zào cǎo píng', + '日中为市' => ' rì zhōng wéi shì', + '是非颠倒' => ' shì fēi diān dǎo', + '食不重味' => ' shí bù chóng wèi', + '毁家纾难' => ' huǐ jiā shū nàn', + '一走了之' => ' yī zǒu liǎo zhī', + '一言为重' => ' yī yán wéi zhòng', + '上半部分' => ' shàng bàn bù fèn', + '杀彘教子' => ' shā zhì jiào zǐ', + '诗书发冢' => ' shī shū fà zhǒng', + '生发未燥' => ' shēng fà wèi zào', + '桑户棬枢' => ' sāng hù juàn shū', + '指导思想' => ' zhí dǎo sī xiǎng', + '三十六行' => ' sān shí liù háng', + '开疆拓宇' => ' kāi jiāng tuò yǔ', + '不治之症' => ' bù zhì zhī zhèng', + '斫雕为朴' => ' zhuó diāo wéi pǔ', + '口尚乳臭' => ' kǒu shàng rǔ xiù', + '智尽能索' => ' zhì jìn néng suǒ', + '口燥唇干' => ' kǒu zào chún gān', + '人类行为' => ' rén lèi xíng wéi', + '化为泡影' => ' huà wéi pāo yǐng', + '大洋中脊' => ' dà yáng zhōng jǐ', + '糠豆不赡' => ' kang dou bu shan', + '左支右调' => ' zuǒ zhī yòu tiáo', + '悬首吴阙' => ' xuán shǒu wú què', + '兴妖作孽' => ' xīng yāo zuò niè', + '秀出班行' => ' xiù chū bān háng', + '公共事业' => ' gōng gòng shì yè', + '公共假期' => ' gōng gòng jià qī', + '公共厕所' => ' gōng gòng cè suǒ', + '刑讯逼供' => ' xíng xùn bī gòng', + '悬鼓待椎' => ' xuán gǔ dài zhuī', + '轩鹤冠猴' => ' xuān hè guàn hóu', + '供不应求' => ' gōng bù yìng qiú', + '学生宿舍' => ' xué shēng sù shè', + '片长末技' => ' piàn cháng mò jì', + '埙篪相和' => ' xūn chí xiāng hè', + '公共汽车' => ' gōng gòng qì chē', + '唱高调儿' => ' chàng gāo diào r', + '没收财产' => ' mò shōu cái chǎn', + '万古长存' => ' wàn gǔ cháng cún', + '兴文匽武' => ' xīng wén diào wǔ', + '形孤影只' => ' xíng gū yǐng zhī', + '七长八短' => ' qī cháng bā duǎn', + '王孙公子' => ' wáng sūn gōng zǐ', + '地壳运动' => ' dì qiào yùn dòng', + '理论框架' => ' lǐ lùn kuàng jià', + '指雁为羹' => ' zhǐ yàn wéi gēng', + '咳唾成珠' => ' ké tuò chéng zhū', + '抗颜为师' => ' kàng yán wéi shī', + '直言切谏' => ' zhí yán qiē jiàn', + '厚养薄葬' => ' hòu yǎng bó zàng', + '指天为誓' => ' zhǐ tiān wéi shì', + '知疼着热' => ' zhī téng zháo rè', + '认影为头' => ' rèn yǐng wéi tóu', + '人心丧尽' => ' rén xīn sàng jìn', + '溘然长逝' => ' kè rán cháng shì', + '指树为姓' => ' zhǐ shù wéi xìng', + '数往知来' => ' shǔ wǎng zhī lái', + '三省吾身' => ' sān xǐng wú shēn', + '原子半径' => ' yuán zǐ bàn jìng', + '转灾为福' => ' zhuǎn zāi wéi fú', + '只身孤影' => ' zhī shēn gū yǐng', + '刻章琢句' => ' kè zhāng zhuó jù', + '指山说磨' => ' zhǐ shān shuō mò', + '人烟浩穰' => ' rén yān hào rǎng', + '不揣冒昧' => ' bù chuǎi mào mèi', + '化学反应' => ' huà xué fǎn yìng', + '鸠形鹄面' => ' jiū xíng hú miàn', + '三陪小姐' => ' sān péi xiǎo jie', + '筑舍道傍' => ' zhù shè dào bàng', + '气冲斗牛' => ' qì chōng dǒu niú', + '钻穴逾垣' => ' zuàn xué yú yuán', + '尽入彀中' => ' jìn rù gòu zhōng', + '詹言曲说' => ' zhān yán qǔ shuō', + '埋天怨地' => ' mán tiān yuàn dì', + '累卵之危' => ' lěi luǎn zhī wēi', + '参辰日月' => ' shēn chén rì yuè', + '斩尽杀绝' => ' zhǎn jìn shā jué', + '贼子乱臣' => ' zéi zǐ luàn chén', + '钻头就锁' => ' zuàn tóu jiù suǒ', + '尽美尽善' => ' jìn měi jìn shàn', + '醉山颓倒' => ' zuì shān tuí dǎo', + '善为说辞' => ' shàn wéi shuō cí', + '斩将刈旗' => ' zhǎn jiàng yì qí', + '累瓦结绳' => ' lěi wǎ jié shéng', + '累屋重架' => ' lěi wū chóng jià', + '似箭在弦' => ' sì jiàn zài xián', + '曾不惨然' => ' zeng bu chan ran', + '尽其所长' => ' jìn qí suǒ cháng', + '桑土绸缪' => ' sāng tǔ chóu miù', + '人多阙少' => ' rén duō què shǎo', + '旧话重提' => ' jiù huà chóng tí', + '思潮澎湃' => ' sī cháo péng pài', + '沾沾自好' => ' zhān zhān zì hào', + '如应斯响' => ' rú yìng sī xiǎng', + '诘屈磝碻' => ' jié qū bìng zhòu', + '白喉杆菌' => ' bái hóu gǎn jūn', + '少不经事' => ' shào bù jīng shì', + '死亡枕藉' => ' sǐ wáng zhěn jiè', + '十字转门' => ' shí zì zhuàn mén', + '贼臣乱子' => ' zéi chén luàn zǐ', + '少年得志' => ' shào nián dé zhì', + '少小无猜' => ' shào xiǎo wú cāi', + '励精更始' => ' lì jīng gēng shǐ', + '舍身为国' => ' shě shēn wéi guó', + '揭箧担囊' => ' jiē qiè dān náng', + '丹瑞大将' => ' dān ruì dà jiàng', + '松柏之志' => ' sōng bǎi zhī zhì', + '反应堆芯' => ' fǎn yìng duī xīn', + '月没参横' => ' yuè mò shēn héng', + '折箭为誓' => ' shé jiàn wéi shì', + '作舍道边' => ' zuò shè dào biān', + '累见不鲜' => ' lěi jiàn bù xiǎn', + '立党为公' => ' lì dǎng wèi gōng', + '肆虐横行' => ' sì nüè héng xíng', + '长幼有序' => ' zhǎng yòu yǒu xù', + '日朘月减' => ' rì juān yuè jiǎn', + '日久岁长' => ' rì jiǔ suì cháng', + '捐身徇义' => ' juān shēn xùn yì', + '三藏法师' => ' sān zàng fǎ shī', + '转忧为喜' => ' zhuǎn yōu wéi xǐ', + '一笑了之' => ' yī xiào liǎo zhī', + '识微知著' => ' shí wēi zhī zhuó', + '日引月长' => ' rì yǐn yuè cháng', + '杼柚其空' => ' zhù zhóu qí kōng', + '杼柚空虚' => ' zhù zhóu kōng xū', + '祝咽祝哽' => ' zhù yān zhù gěng', + '世界冠军' => ' shì jiè guàn jūn', + '印象主义' => ' yìn xiàng zhǔ yì', + '圈牢养物' => ' juàn láo yǎng wù', + '开疆拓土' => ' kāi jiāng tuò tǔ', + '褚小怀大' => ' zhǔ xiǎo huái dà', + '一身两役' => ' yī shēn liǎng yì', + '日月参辰' => ' rì yuè shēn chén', + '祝鮀之佞' => ' zhù tuó zhī nìng', + '尸居龙见' => ' shī jū lóng xiàn', + '什袭珍藏' => ' shí xí zhēn cáng', + '助天为虐' => ' zhù tiān wéi nüè', + '融洽无间' => ' róng qià wú jiàn', + '柱石之坚' => ' zhù shí zhī jiān', + '收旗卷伞' => ' shōu qí juàn sǎn', + '转祸为福' => ' zhuǎn huò wéi fú', + '珠宫贝阙' => ' zhū gōng bèi què', + '逐机应变' => ' zhú jī yìng biàn', + '卷帙浩繁' => ' juàn zhì hào fán', + '助纣为虐' => ' zhù zhòu wéi nüè', + '多钱善贾' => ' duō qián shàn gǔ', + '神武挂冠' => ' shén wǔ guà guàn', + '劳动合同' => ' láo dòng hé tong', + '白苋紫茄' => ' bái xiàn zǐ qié', + '多重国籍' => ' duō chóng guó jí', + '身无长物' => ' shēn wú cháng wù', + '日长一线' => ' rì cháng yī xiàn', + '适应能力' => ' shì yìng néng lì', + '理性知识' => ' lǐ xìng zhī shi', + '不了了之' => ' bù liǎo liǎo zhī', + '人自为政' => ' rén zì wéi zhèng', + '审曲面埶' => ' shěn qǔ miàn xīn', + '人中狮子' => ' rén zhōng shī zǐ', + '种瓜得瓜' => ' zhòng guā dé guā', + '种豆得豆' => ' zhòng dòu dé dòu', + '审曲面势' => ' shěn qǔ miàn shì', + '专横跋扈' => ' zhuān hèng bá hù', + '深切著白' => ' shēn qiè zhù bái', + '信息灵通' => ' xìn xi líng tōng', + '内线消息' => ' nèi xiàn xiāo xi', + '少不更事' => ' shào bù gēng shì', + '弹斤估两' => ' tán jīn gū liǎng', + '因缘为市' => ' yīn yuán wéi shì', + '应答如响' => ' yìng dá rú xiǎng', + '令原之戚' => ' líng yuán zhī qī', + '陵劲淬砺' => ' líng jìng cuì lì', + '弹丸脱手' => ' tán wán tuō shǒu', + '临难铸兵' => ' lín nàn zhù bīng', + '临难苟免' => ' lín nàn gǒu miǎn', + '临机应变' => ' lín jī yìng biàn', + '应用技术' => ' yìng yòng jì shù', + '应弦而倒' => ' yìng xián ér dǎo', + '流年似水' => ' liú nián sì shuǐ', + '钦差大臣' => ' qīn chāi dà chén', + '挈瓶之知' => ' qiè píng zhī zhì', + '引为鉴戒' => ' yǐn wéi jiàn jiè', + '弹性蛋白' => ' tán xìng dàn bái', + '人间佛教' => ' rén jiān fó jiào', + '人车混行' => ' rén chē hún xíng', + '印累绶若' => ' yìn léi shòu ruò', + '搂头盖脸' => ' lōu tóu gài liǎn', + '淫言媟语' => ' yín yán liǎng yǔ', + '凌云之志' => ' líng yún zhī zhì', + '铜筋铁肋' => ' tóng jīn tiě lèi', + '人满为患' => ' rén mǎn wéi huàn', + '呷醋节帅' => ' xiā cù jié shuài', + '啮血为盟' => ' niè xuè wéi méng', + '一言为定' => ' yī yán wéi dìng', + '先睹为快' => ' xiān dǔ wéi kuài', + '熬更守夜' => ' áo gēng shǒu yè', + '破愁为笑' => ' pò chóu wéi xiào', + '攀蟾折桂' => ' pān chán shé guì', + '系统更新' => ' xì tǒng gēng xīn', + '农业银行' => ' nóng yè yín háng', + '倭黑猩猩' => ' wō hēi xīng xing', + '为山止篑' => ' wéi shān zhǐ kuì', + '衣被群生' => ' yì bèi qún shēng', + '燕京啤酒' => ' yān jīng pí jǐu', + '牛听弹琴' => ' niú tīng tán qín', + '借尸还魂' => ' jiè shī huán hún', + '显露头角' => ' xiǎn lù tóu jiǎo', + '凶神恶煞' => ' xiōng shén è shà', + '相对误差' => ' xiāng duì wù chā', + '掊斗折衡' => ' pǒu dǒu zhé héng', + '扭亏为盈' => ' niǔ kuī wéi yíng', + '松筠之节' => ' sōng jūn zhī jié', + '漏尽更阑' => ' lòu jìn gēng lán', + '人民银行' => ' rén mín yín háng', + '内助之贤' => ' nèi zhù zhī xián', + '游闲公子' => ' yóu xián gōng zǐ', + '围魏救赵' => ' wéi wèi jiù zhào', + '量才而为' => ' liàng cái ér wéi', + '弹冠振衣' => ' tán guān zhèn yī', + '了无生趣' => ' liǎo wú shēng qù', + '燎如观火' => ' liǎo rú guān huǒ', + '事危累卵' => ' shì wēi lěi luǎn', + '撩火加油' => ' liáo huǒ jiā yóu', + '玉尺量才' => ' yù chǐ liáng cái', + '撩蜂剔蝎' => ' liáo fēng tì xiē', + '优游涵泳' => ' yōu yóu hán yǒng', + '语笑喧哗' => ' yǔ xiào xuān huá', + '情见势屈' => ' qíng xiàn shì qū', + '清静无为' => ' qīng jìng wú wéi', + '索尽枯肠' => ' suǒ jìn kū cháng', + '请假回家' => ' qǐng jià huí jiā', + '痛深恶绝' => ' tòng shēn wù jué', + '因果报应' => ' yīn guǒ bào yìng', + '韬光俟奋' => ' tāo guāng sì fèn', + '调和阴阳' => ' tiáo hé yīn yáng', + '调和鼎鼐' => ' tiáo hé dǐng nài', + '裂裳裹足' => ' liè cháng guǒ zú', + '情绪反应' => ' qíng xù fǎn yìng', + '袒裼裸裎' => ' tǎn xī luǒ chéng', + '情深似海' => ' qíng shēn sì hǎi', + '笼络人心' => ' lǒng luò rén xīn', + '龙举云兴' => ' lóng jǔ yún xīng', + '贪小便宜' => ' tān xiǎo pián yi', + '什一奉献' => ' shí yī fèng xiàn', + '瓮尽杯干' => ' wèng jìn bēi gān', + '埒才角妙' => ' liè cái jué miào', + '连编累牍' => ' lián biān lěi dú', + '团体冠军' => ' tuán tǐ guàn jūn', + '羽扇纶巾' => ' yǔ shàn guān jīn', + '取长补短' => ' qǔ cháng bǔ duǎn', + '渊涓蠖濩' => ' yuān juān huò hù', + '蠡酌管窥' => ' lǐ zhuó guǎn kuī', + '青林黑塞' => ' qīng lín hēi sài', + '例行差事' => ' lì xíng chāi shì', + '燕京大学' => ' yān jīng dà xué', + '玉质金相' => ' yù zhì jīn xiàng', + '营业时候' => ' yíng yè shí hou', + '远不间亲' => ' yuǎn bù jiàn qīn', + '送子观音' => ' sòng zǐ guān yīn', + '地方停车' => ' dì fang tíng chē', + '充分就业' => ' chōng fèn jìu yè', + '普天率土' => ' pǔ tiān shuài tǔ', + '万家生佛' => ' wàn jiā shēng fó', + '千差万别' => ' qiān chā wàn bié', + '液晶电视' => ' yè jīng diàn shì', + '咬姜呷醋' => ' yǎo jiāng xiā cù', + '棋输先着' => ' qí shū xiān zhāo', + '明珠弹雀' => ' míng zhū tán què', + '千了万当' => ' qiān le wàn dàng', + '燕处焚巢' => ' yàn chǔ fén cháo', + '燕处危巢' => ' yàn chǔ wēi cháo', + '公共道德' => ' gōng gòng dào dé', + '其应如响' => ' qí yìng rú xiǎng', + '乾端坤倪' => ' qián duān kūn ní', + '民事调解' => ' mín shì tiáo jiě', + '抟沙嚼蜡' => ' tuán shā jiáo là', + '万别千差' => ' wàn bié qiān chā', + '燕骏千金' => ' yān jùn qiān jīn', + '前功尽弃' => ' qián gōng jìn qì', + '磨砻镌切' => ' mó lóng juān qiē', + '乾嘉学派' => ' qián jiā xué pài', + '言笑晏晏' => ' yán xiào yàn yàn', + '严刑逼供' => ' yán xíng bī gòng', + '同型配子' => ' tóng xíng pèi zǐ', + '妖由人兴' => ' yāo yóu rén xīng', + '咬血为盟' => ' yǎo xuè wéi méng', + '一笑置之' => ' yī xiào zhì zhī', + '望闻问切' => ' wàng wén wèn qiē', + '兴亡祸福' => ' xīng wáng huò fú', + '哭丧着脸' => ' kū sāng zhe liǎn', + '无穷无尽' => ' wú qióng wú jìn', + '行为不端' => ' xíng wéi bù duān', + '行为不检' => ' xíng wéi bù jiǎn', + '行为规范' => ' xíng wéi guī fàn', + '行为能力' => ' xíng wéi néng lì', + '晚食当肉' => ' wǎn shí dàng ròu', + '兴亡继绝' => ' xīng wáng jì jué', + '公共秩序' => ' gōng gòng zhì xù', + '同恶相恤' => ' tóng wù xiāng xù', + '言必有中' => ' yán bì yǒu zhòng', + '图穷匕见' => ' tú qióng bǐ xiàn', + '燕昭市骏' => ' yān zhāo shì jùn', + '言之过甚' => ' yán zhī guò shèn', + '佛朗机铳' => ' fó lǎng jī chòng', + '头童齿豁' => ' tóu tóng chǐ huò', + '冤家对头' => ' yuān jia duì tóu', + '明月入怀' => ' míng yuè rù huái', + '要价还价' => ' yào jià huán jià', + '夜静更阑' => ' yè jìng gēng lán', + '铺张扬厉' => ' pū zhāng yáng lì', + '免疫反应' => ' miǎn yì fǎn yìng', + '相鼠有皮' => ' xiàng shǔ yǒu pí', + '骈肩累足' => ' pián jiān lěi zú', + '片鳞只甲' => ' piàn lín zhī jiǎ', + '五行并下' => ' wǔ háng bìng xià', + '片文只事' => ' piàn wén zhī shì', + '和平共处' => ' hé píng gòng chǔ', + '傻瓜相机' => ' shǎ guā xiàng jī', + '未艾方兴' => ' wèi ài fāng xīng', + '夕寐宵兴' => ' xī mèi xiāo xīng', + '值得称赞' => ' zhí de chēng zàn', + '小廉曲谨' => ' xiǎo lián qǔ jǐn', + '无量寿佛' => ' wú liàng shòu fó', + '未了公案' => ' wèi liǎo gōng àn', + '孝子顺孙' => ' xiào zǐ shùn sūn', + '孝子贤孙' => ' xiào zǐ xián sūn', + '橡皮钉子' => ' xiàng pí dìng zǐ', + '能者为师' => ' néng zhě wéi shī', + '邪不干正' => ' xié bù gān zhèng', + '协调发展' => ' xié tiáo fā zhǎn', + '心瞻魏阙' => ' xīn zhān wèi què', + '兴邦立国' => ' xīng bāng lì guó', + '骈肩累迹' => ' pián jiān lěi jì', + '皮相之谈' => ' pí xiàng zhī tán', + '兴词构讼' => ' xīng cí gòu sòng', + '五行生克' => ' wǔ háng shēng kè', + '温席扇枕' => ' wēn xí shān zhěn', + '煞有介事' => ' shà yǒu jiè shì', + '偶联反应' => ' ǒu lián fǎn yìng', + '停酒止乐' => ' tíng jǐu zhǐ yuè', + '停车位置' => ' tíng chē wèi zhi', + '闻风而兴' => ' wén fēng ér xīng', + '文行出处' => ' wén xíng chū chǔ', + '贫困潦倒' => ' pín kùn liáo dǎo', + '频率成分' => ' pín lǜ chéng fèn', + '五行相克' => ' wǔ háng xiāng kè', + '命名作业' => ' mìng míng zuò yè', + '雾兴云涌' => ' wù xīng yún yǒng', + '凭几据杖' => ' píng jī jù zhàng', + '味同嚼蜡' => ' wèi tóng jiáo là', + '恶醉强酒' => ' wù zuì qiǎng jiǔ', + '诬良为盗' => ' wū liáng wéi dào', + '温枕扇席' => ' wēn zhěn shān xí', + '片长薄技' => ' piàn cháng bó jì', + '片甲不还' => ' piàn jiǎ bù huán', + '无肠公子' => ' wú cháng gōng zǐ', + '一了百了' => ' yī liǎo bǎi liǎo', + '云兴霞蔚' => ' yún xīng xiá wèi', + '扪参历井' => ' mén shēn lì jǐng', + '一之谓甚' => ' yī zhī wèi shèn', + '百喙莫辩' => ' bǎi huì mò biàn', + '分毫之差' => ' fēn háo zhī chā', + '一之为甚' => ' yī zhī wéi shèn', + '提起精神' => ' tí qǐ jīng shen', + '没羞没臊' => ' méi xīu méi sào', + '白发红颜' => ' bái fà hóng yán', + '白发苍颜' => ' bái fà cāng yán', + '熟思审处' => ' shú sī shěn chǔ', + '分解代谢' => ' fēn jiě dài xiè', + '束身自好' => ' shù shēn zì hào', + '左右为难' => ' zuǒ yòu wéi nán', + '八方呼应' => ' bā fāng hū yìng', + '束戈卷甲' => ' shù gē juàn jiǎ', + '八方风雨' => ' bā fāng fēng yǔ', + '调皮捣蛋' => ' tiáo pí dǎo dàn', + '洋底地壳' => ' yáng dǐ dì qiào', + '没有关系' => ' méi yǒu guān xi', + '熬姜呷醋' => ' áo jiāng xiā cù', + '安守本分' => ' ān shǒu běn fèn', + '作歹为非' => ' zuò dǎi wéi fēi', + '泄露天机' => ' xiè lòu tiān jī', + '五倍子虫' => ' wǔ bèi zǐ chóng', + '调墨弄笔' => ' tiáo mò nòng bǐ', + '为时过早' => ' wéi shí guò zǎo', + '炸土豆片' => ' zhá tǔ dòu piàn', + '朝欢暮乐' => ' zhāo huān mù lè', + '等差级数' => ' děng chā jí shù', + '为善最乐' => ' wéi shàn zuì lè', + '为德不终' => ' wéi dé bù zhōng', + '竹篮打水' => ' zhú lán dá shuǐ', + '枕曲藉糟' => ' zhěn qū jiè zāo', + '竭尽全力' => ' jié jìn quán lì', + '为时未晚' => ' wéi shí wèi wǎn', + '朝折暮折' => ' zhāo shé mù shé', + '朝攀暮折' => ' zhāo pān mù shé', + '一念之差' => ' yī niàn zhī chā', + '空地导弹' => ' kòng dì dǎo dàn', + '一弹指顷' => ' yī tán zhǐ qǐng', + '一矢中的' => ' yī shǐ zhòng dì', + '中子俘获' => ' zhōng zǐ fú huò', + '积年累月' => ' jī nián lěi yuè', + '没有差别' => ' méi yǒu chā bié', + '移山倒海' => ' yí shān dǎo hǎi', + '私生子女' => ' sī shēng zǐ nǔ:', + '一年半载' => ' yī nián bàn zǎi', + '坐不重席' => ' zuò bù chóng xí', + '一无所长' => ' yī wú suǒ cháng', + '一年到头' => ' yì nián dào tóu', + '长目飞耳' => ' cháng mù fēi ěr', + '虱胫虮肝' => ' shī jìng jī gān', + '歪歪倒倒' => ' wāi wāi dǎo dǎo', + '脱袍退位' => ' tuō páo tuì wèi', + '拖麻拽布' => ' tuō má zhuài bù', + '魂不守舍' => ' hún bù shǒu shè', + '长虑却顾' => ' cháng lǜ què gù', + '屯蹶否塞' => ' tún juě fǒu sāi', + '总体要求' => ' zǒng tǐ yāo qiú', + '推轮捧毂' => ' tuī lún pěng gū', + '书本知识' => ' shū běn zhī shi', + '长虑后顾' => ' cháng lǜ hòu gù', + '长虑顾后' => ' cháng lǜ gù hòu', + '失马塞翁' => ' shī mǎ sài wēng', + '渣打银行' => ' zhā dǎ yín háng', + '什围伍攻' => ' shí wéi wǔ gōng', + '兔角龟毛' => ' tu jiao gui mao', + '安时处顺' => ' ān shí chǔ shùn', + '投资银行' => ' tóu zī yín háng', + '黎明时分' => ' lí míng shí fèn', + '淡泊明志' => ' dàn bó míng zhì', + '疏不间亲' => ' shū bù jiàn qīn', + '树倒根摧' => ' shù dǎo gēn cuī', + '一多对应' => ' yī duō duì yìng', + '天干地支' => ' tiān gān dì zhī', + '百口莫辩' => ' bǎi kǒu mò biàn', + '参伍错综' => ' cēn wǔ cuò zōng', + '束缊还妇' => ' shù yūn huán fù', + '田父献曝' => ' tián fǔ xiàn pù', + '浪卡子县' => ' làng kǎ zǐ xiàn', + '草头天子' => ' cǎo tóu tiān zǐ', + '梳云掠月' => ' shū yún lüě yuè', + '浪子回头' => ' làng zǐ huí tóu', + '苍颜白发' => ' cāng yán bái fà', + '百载树人' => ' bǎi zǎi shù rén', + '沈鱼落雁' => ' chén yú luò yàn', + '恬淡无为' => ' tián dàn wú wéi', + '百身莫赎' => ' bǎi shēn mò shú', + '刚正不阿' => ' gāng zhèng bù ē', + '切向速度' => ' qiē xiàng sù dù', + '腾腾兀兀' => ' téng téng wū wū', + '白云亲舍' => ' bái yún qīn shè', + '排难解纷' => ' pái nàn jiě fēn', + '一天到晚' => ' yì tiān dào wǎn', + '炸土豆条' => ' zhá tǔ dòu tiáo', + '澎湖群岛' => ' péng hú qún dǎo', + '爱出风头' => ' ài chū fēng tou', + '与世无争' => ' yú shì wú zhēng', + '老少皆宜' => ' lǎo shào jiē yí', + '优游岁月' => ' yōu yóu suì yuè', + '腹笥便便' => ' fù sì pián pián', + '兴灭继绝' => ' xīng miè jì jué', + '考试卷子' => ' kǎo shì juàn zi', + '有志之士' => ' yǒu zhì zhī shì', + '兴旺发达' => ' xīng wàng fā dá', + '与人为善' => ' yǔ rén wéi shàn', + '与世长辞' => ' yǔ shì cháng cí', + '圣德太子' => ' shèng dé tài zǐ', + '老两口儿' => ' lǎo liǎng kǒu r', + '果实累累' => ' guǒ shí lěi lěi', + '自视甚高' => ' zì shì shèn gāo', + '与民更始' => ' yǔ rén gēng shǐ', + '胆大妄为' => ' dǎn dà wàng wéi', + '原始积累' => ' yuán shǐ jī lěi', + '不可胜数' => ' bù kě shèng shǔ', + '九齿钉耙' => ' jǐu chǐ dīng pá', + '组成部分' => ' zǔ chéng bù fen', + '冤家路狭' => ' yuān jia lù xiá', + '优游不断' => ' yōu yóu bù duàn', + '月夕花朝' => ' yuè xī huā zhāo', + '指不胜偻' => ' zhǐ bù shèng lǚ', + '脱骨成佛' => ' tuō gǔ chéng fó', + '缊褐瓢箪' => ' yùn hè piáo dān', + '匀速运动' => ' yún sù yùn dòng', + '核反应堆' => ' hé fǎn yìng duī', + '早占勿药' => ' zǎo zhān wù yào', + '习以为常' => ' xí yǐ wéi cháng', + '网络铁路' => ' wǎng luò tiě lù', + '干净俐落' => ' gān jìng lì luò', + '曾母投杼' => ' zēng mǔ tóu zhù', + '月晕而风' => ' yuè yùn ér fēng', + '腹笥甚宽' => ' fù sì shèn kuān', + '有以善处' => ' yǒu yǐ shàn chǔ', + '月夜花朝' => ' yuè yè huā zhāo', + '芝麻小事' => ' zhī ma xiǎo shì', + '干净利落' => ' gān jìng lì luò', + '褎如充耳' => ' yòu rú chōng ěr', + '事怕行家' => ' shì pà háng jiā', + '于无声处' => ' yú wú shēng chǔ', + '事在人为' => ' shì zài rén wéi', + '有所作为' => ' yǒu suǒ zuò wéi', + '东倒西歪' => ' dōng dǎo xī wāi', + '予智予雄' => ' yú zhì yú xióng', + '石头火锅' => ' shí tou huǒ guō', + '澎湖列岛' => ' péng hú liè dǎo', + '氧乙炔焊' => ' yǎng yǐ quē hàn', + '神出鬼没' => ' shén chū guǐ mò', + '民间故事' => ' mín jiān gù shi', + '溘先朝露' => ' kè xiān zhāo lù', + '氢氧离子' => ' qīng yǎng lí zǐ', + '氢原子核' => ' qīng yuán zǐ hé', + '礼废乐崩' => ' lǐ fèi yuè bēng', + '灭此朝食' => ' miè cǐ zhāo shí', + '绍兴地区' => ' shào xīng dì qū', + '一技之长' => ' yī jì zhī cháng', + '细嚼慢咽' => ' xì jiáo màn yàn', + '知识产业' => ' zhī shi chǎn yè', + '子丑寅卯' => ' zǐ chǒu yín mǎo', + '瞻予马首' => ' zhān yú mǎ shǒu', + '朝歌暮弦' => ' zhāo gē mù xián', + '朝歌夜弦' => ' zhāo gē yè xián', + '漏脯充饥' => ' lòu fǔ chōng jī', + '追趋逐耆' => ' zhuī qū zhú shì', + '朝华夕秀' => ' zhāo huá xī xiù', + '洁身自好' => ' jié shēn zì hào', + '子孙满堂' => ' zǐ sūn mǎn táng', + '绝食抗议' => ' jué shí kàng yì', + '置锥之地' => ' zhì zhuī zhī dì', + '脊椎动物' => ' jǐ zhuī dòng wù', + '百废具兴' => ' bǎi fèi jù xīng', + '尽人皆知' => ' jìn rén jiē zhī', + '不省人事' => ' bù xǐng rén shì', + '乐善好施' => ' lè shàn hào shī', + '栉风酾雨' => ' zhì fēng shī yǔ', + '止戈兴仁' => ' zhǐ gē xīng rén', + '瞎子摸象' => ' xiā zǐ mō xiàng', + '不为所动' => ' bù wéi suǒ dòng', + '不求甚解' => ' bù qiú shèn jiě', + '相体裁衣' => ' xiàng tǐ cái yī', + '不着边际' => ' bù zhuó biān jì', + '橡子面儿' => ' xiàng zi miàn r', + '指山卖磨' => ' zhǐ shān mài mò', + '知识结构' => ' zhī shi jié gòu', + '花朝月夕' => ' huā zhāo yuè xī', + '直系血亲' => ' zhí xì xuè qìng', + '不定冠词' => ' bù dìng guàn cí', + '目下十行' => ' mù xià shí háng', + '指皂为白' => ' zhǐ zào wéi bái', + '尽欢而散' => ' jìn huān ér sàn', + '尽收眼底' => ' jìn shōu yǎn dǐ', + '鼓鼓囊囊' => ' gǔ gǔ nāng nāng', + '长恶靡悛' => ' cháng è mǐ quān', + '取长弃短' => ' qǔ cháng qì duǎn', + '电动葫芦' => ' diàn dòng hú lu', + '神号鬼哭' => ' shén háo guǐ kū', + '为国为民' => ' wéi guó wéi mín', + '畏首畏尾' => ' wèi shǒu wèi wěi', + '番茄红素' => ' fān qié hóng sù', + '首要任务' => ' shǒu yào rèn wu', + '为蛇添足' => ' wéi shé tiān zú', + '饶舌音乐' => ' ráo shé yīn yuè', + '欺人太甚' => ' qī rén tài shèn', + '为数不少' => ' wéi shù bù shǎo', + '异曲同工' => ' yì qǔ tóng gōng', + '神至之笔' => ' shén zhì zhī bǐ', + '北斗七星' => ' běi dǒu qī xīng', + '超然独处' => ' chāo rán dú chǔ', + '巢居穴处' => ' cháo jū xué chǔ', + '权利要求' => ' quán lì yāo qíu', + '畏威怀德' => ' wèi wēi huái dé', + '化险为夷' => ' huà xiǎn wéi yí', + '违法行为' => ' wéi fǎ xíng wéi', + '昼乾夕惕' => ' zhòu qián xī tì', + '周郎顾曲' => ' zhōu láng gù qǔ', + '故地重游' => ' gù dì chóng yóu', + '操作系统' => ' cāo zuō xì tǒng', + '诗肠鼓吹' => ' shī chá gǔ chuì', + '电磁干扰' => ' diàn cí gān rǎo', + '电子器件' => ' diàn zǐ qì jiàn', + '威望素著' => ' wēi wàng sù zhù', + '长揖不拜' => ' cháng yī bù bài', + '光禄大夫' => ' guāng lù dài fu', + '鞠躬尽瘁' => ' jū gōng jìn cuì', + '长驱直入' => ' cháng qū zhí rù', + '文过遂非' => ' wén guò suí fēi', + '玩儿不转' => ' wán ér bù zhuàn', + '颠三倒四' => ' diān sān dǎo sì', + '深文曲折' => ' shēn wén qǔ shé', + '枉曲直凑' => ' wǎng qǔ zhí còu', + '汇业银行' => ' huì yè yín háng', + '颠来倒去' => ' diān lái dǎo qù', + '放不下心' => ' fàng bu xià xīn', + '放下包袱' => ' fàng xia bāo fu', + '文房四侯' => ' wén fáng sì hòu', + '先入为主' => ' xiān rù wéi zhǔ', + '危于累卵' => ' wēi yú lěi luǎn', + '望风披靡' => ' wàng fēng pī mǐ', + '长途奔袭' => ' cháng tú bēn xí', + '擢发难数' => ' zhuó fà nán shǔ', + '深厉浅揭' => ' shēn lì qiǎn qì', + '委委佗佗' => ' wēi wēi tuó tuó', + '狼子兽心' => ' láng zǐ shòu xīn', + '瑟调琴弄' => ' sè tiáo qín nòng', + '前半晌儿' => ' qián bàn shǎng r', + '久安长治' => ' jiǔ ān cháng zhì', + '尽忠竭力' => ' jìn zhōng jié lì', + '深谷为陵' => ' shēn gǔ wéi líng', + '朝生暮死' => ' zhāo shēng mù sǐ', + '朝升暮合' => ' zhāo shēng mù gě', + '总会计师' => ' zǒng kuài jì shī', + '裙屐少年' => ' qún jī shào nián', + '杀妻求将' => ' shā qī qiú jiàng', + '子夏悬鹑' => ' zǐ xià xuán chún', + '曲终人散' => ' qǔ zhōng rén sàn', + '朝令暮改' => ' zhāo lìng mù gǎi', + '朝经暮史' => ' zhāo jīng mù shǐ', + '朝生夕死' => ' zhāo shēng xī sǐ', + '朝趁暮食' => ' zhāo chèn mù shí', + '施工合同' => ' shī gōng hé tong', + '太古洋行' => ' tài gǔ yáng háng', + '似水流年' => ' sì shuǐ liú nián', + '扇枕温席' => ' shān zhěn wēn xí', + '旷日累时' => ' kuàng rì lěi shí', + '款曲周至' => ' kuǎn qǔ zhōu zhì', + '十夫楺椎' => ' shí fū zhī zhuī', + '朝更暮改' => ' zhāo gèng mù gǎi', + '生死未卜' => ' shēng sǐ wèi bǔ', + '长途直拨' => ' cháng tú zhí bō', + '十夫桡椎' => ' shí fū ráo zhuī', + '审己度人' => ' shěn jǐ duó rén', + '食物中毒' => ' shí wù zhòng dú', + '十四行诗' => ' shí sì háng shī', + '收拾残局' => ' shōu shi cán jú', + '进退中度' => ' jìn tuì zhòng dù', + '善财童子' => ' shàn cái tóng zǐ', + '曲意承迎' => ' qǔ yì chéng yíng', + '朝衣东市' => ' zhāo yī dōng shì', + '累牍连篇' => ' lěi dú lián piān', + '硕望宿德' => ' shuò wàng xiǔ dé', + '金相玉质' => ' jīn xiàng yù zhì', + '钻冰取火' => ' zuàn bīng qǔ huǒ', + '纵曲枉直' => ' zòng qǔ wǎng zhí', + '走为上策' => ' zǒu wéi shàng cè', + '孀妻弱子' => ' shuāng qī ruò zǐ', + '博闻强识' => ' bó wén qiáng zhì', + '瑟弄琴调' => ' sè nòng qín tiáo', + '风尘仆仆' => ' fēng chén pú pú', + '男性厌恶' => ' nán xìng yàn wù', + '通同一气' => ' tōng tóng yī yì', + '男孩乐队' => ' nán hái yuè duì', + '拜人为师' => ' bài rén wéi shī', + '不了不当' => ' bù liǎo bù dàng', + '变危为安' => ' biàn wēi wéi ān', + '遂心快意' => ' suí xīn kuài yì', + '遂迷忘反' => ' suí mí wàng fǎn', + '拾级而上' => ' shè jí ér shàng', + '薄弱环节' => ' bó ruò huán jié', + '薄命佳人' => ' bó mìng jiā rén', + '挑拨离间' => ' tiǎo bō lí jiàn', + '挑拨是非' => ' tiǎo bō shì fēi', + '标记原子' => ' biāo jì yuán zǐ', + '理性认识' => ' lǐ xìng rèn shi', + '屏气敛息' => ' bǐng qì liǎn xī', + '遂非文过' => ' suí fēi wén guò', + '拨乱为治' => ' bō luàn wéi zhì', + '肆意横行' => ' sì yì héng xíng', + '夙兴昧旦' => ' sù xīng mèi dàn', + '宋词元曲' => ' sòng cí yuán qǔ', + '初露头角' => ' chū lù tóu jiǎo', + '不遑启处' => ' bù huáng qǐ chǔ', + '不了而了' => ' bù liǎo ér liǎo', + '泰然处之' => ' tài rán chǔ zhī', + '叹观止矣' => ' tàn guān zhǐ yǐ', + '首都领地' => ' shǒu dū lǐng dì', + '长恶不悛' => ' cháng è bù quān', + '实验研究' => ' shí yàn yán jiū', + '同工异曲' => ' tóng gōng yì qǔ', + '调朱傅粉' => ' tiáo zhū fù fěn', + '为非作歹' => ' wéi fēi zuò dǎi', + '力尽神危' => ' lì jìn shén wēi', + '出没无常' => ' chū mò wú cháng', + '并为一谈' => ' bìng wéi yī tán', + '投传而去' => ' tóu zhuàn ér qù', + '无以为生' => ' wú yǐ wéi shēng', + '泰来否往' => ' tài lái pǐ wǎng', + '排忧解难' => ' pái yōu jiě nàn', + '隋珠弹雀' => ' suí zhū tán què', + '别无长物' => ' bié wú cháng wù', + '别开蹊径' => ' bié kāi xī jìng', + '百废俱兴' => ' bǎi fèi jù xīng', + '别别扭扭' => ' biè biè niú niu', + '标题音乐' => ' biāo tí yīn yuè', + '岁序更新' => ' suì xù gēng xīn', + '嗒然若丧' => ' tà rán ruò sàng', + '韬戈卷甲' => ' tāo gē juàn jiǎ', + '弹剑作歌' => ' tán jiàn zuò gē', + '优哉游哉' => ' yōu zāi yóu zāi', + '北门锁钥' => ' běi mén suǒ yuè', + '切磋琢磨' => ' qiē cuō zhuó mó', + '本本分分' => ' běn běn fèn fēn', + '李氏朝鲜' => ' lǐ shì cháo xiǎn', + '本相毕露' => ' běn xiàng bì lù', + '碧波荡漾' => ' bì bō dàng yàng', + '蔽聪塞明' => ' bì cōnɡ sè mínɡ', + '闭明塞聪' => ' bì míng sè cōng', + '四方之志' => ' sì fāng zhī zhì', + '鞭辟着里' => ' biān bì zhuó lǐ', + '用尽心机' => ' yòng jìn xīn jī', + '欧阳予倩' => ' oū yáng yú qiàn', + '十行俱下' => ' shí háng jù xià', + '调丝品竹' => ' tiáo sī pǐn zhú', + '包皮环切' => ' bāo pí huán qiē', + '男女老少' => ' nán nǚ lǎo shào', + '电子工业' => ' diàn zǐ gōng yè', + '蛇蝎为心' => ' shé xiē wéi xīn', + '唯唯否否' => ' wěi wěi fǒu fǒu', + '兆电子伏' => ' zhào diàn zǐ fú', + '深恶痛疾' => ' shēn wù tòng jí', + '捏脊治疗' => ' niē jǐ zhì liáo', + '铄古切今' => ' shuò gǔ qiē jīn', + '暴露文学' => ' bào lòu wén xué', + '助桀为暴' => ' zhù jié wéi bào', + '唐虞之治' => ' táng yú zhī zhì', + '才占八斗' => ' cái zhān bā dǒu', + '采购合同' => ' cǎi gòu hé tong', + '主客颠倒' => ' zhǔ kè diān dǎo', + '助桀为虐' => ' zhù jié wéi nüè', + '抱柱之信' => ' bào zhù zhī xìn', + '抱子弄孙' => ' bào zǐ nòng sūn', + '悲悲切切' => ' bēi bēi qiè qiē', + '卑辞重币' => ' bēi cí zhòng bì', + '北斗之尊' => ' běi dǒu zhī zūn', + '顺蔓摸瓜' => ' shùn wàn mō guā', + '前半天儿' => ' qián bàn tiān r', + '甚感诧异' => ' shèn gǎn chà yì', + '才薄智浅' => ' cāi bó zhì qiǎn', + '不知颠倒' => ' bù zhī diān dǎo', + '不着疼热' => ' bù zhuó téng rè', + '削铅笔机' => ' xiāo qiān bǐ jī', + '铸剑为犁' => ' zhù jiàn wéi lí', + '背曲腰躬' => ' bèi qǔ yāo gōng', + '捧腹绝倒' => ' pěng fù jué dǎo', + '削职为民' => ' xuē zhí wéi mín', + '丧失殆尽' => ' sàng shī dài jìn', + '率土归心' => ' shuài tǔ guī xīn', + '调词架讼' => ' tiáo cí jià sòng', + '处高临深' => ' chǔ gāo lín shēn', + '电子网络' => ' diàn zǐ wǎng luò', + '电子警察' => ' diàn zǐ jǐng chá', + '政治避难' => ' zhèng zhì bì nàn', + '放热反应' => ' fàng rè fǎn yìng', + '待时守分' => ' dài shí shǒu fèn', + '矮子观场' => ' ǎi zǐ guān cháng', + '吹叶嚼蕊' => ' chuī yè jiáo ruǐ', + '音乐学院' => ' yīn yuè xué yuàn', + '处变不惊' => ' chǔ biàn bù jīng', + '电子文件' => ' diàn zǐ wén jiàn', + '应有尽有' => ' yīng yǒu jìn yǒu', + '高丽王朝' => ' gāo lí wáng cháo', + '应用科学' => ' yìng yòng kē xué', + '鲜为人知' => ' xiǎn wéi rén zhī', + '除患兴利' => ' chú huàn xīng lì', + '重足屏息' => ' chóng zú bǐng xī', + '重振旗鼓' => ' chóng zhèn qí gǔ', + '应试教育' => ' yìng shì jiào yù', + '重兴旗鼓' => ' chóng xīng qí gǔ', + '措置失当' => ' cuò zhì shī dàng', + '悄无声息' => ' qiǎo wú shēng xī', + '黑咕隆咚' => ' hēi gū lōng dōng', + '电子邮件' => ' diàn zǐ yóu jiàn', + '非杠杆化' => ' fēi gàng gǎn huà', + '感性认识' => ' gǎn xìng rèn shi', + '鞭长莫及' => ' biān cháng mò jí', + '没颠没倒' => ' méi diān méi dǎo', + '春色撩人' => ' chūn sè liáo rén', + '青藏铁路' => ' qīng zàng tiě lù', + '唇干口燥' => ' chún gān kǒu zào', + '恶意中伤' => ' è yì zhòng shāng', + '怒发冲冠' => ' nù fà chōng guān', + '电子层数' => ' diàn zǐ céng shù', + '随机效应' => ' suí jī xiào yìng', + '随行就市' => ' suí háng jiù shì', + '随风倒柳' => ' suí fēng dǎo lǐu', + '当头棒喝' => ' dāng tóu bàng hè', + '随风倒舵' => ' suí fēng dǎo duò', + '难兄难弟' => ' nàn xiōng nàn dì', + '敢为人先' => ' gǎn wéi rén xiān', + '改善关系' => ' gǎi shàn guān xi', + '电子商务' => ' diàn zǐ shāng wù', + '黄毛丫头' => ' huáng máo yā tou', + '重熙累洽' => ' chóng xī lěi qià', + '非分之念' => ' fēi fèn zhī niàn', + '知之甚微' => ' zhī zhī shèn wēi', + '化枭为鸠' => ' huà xiāo wéi jiū', + '哗世取宠' => ' huá shì qǔ chǒng', + '化鸱为凤' => ' huà chī wéi fèng', + '孔子学院' => ' kǒng zǐ xué yuàn', + '鹄峙鸾停' => ' hú zhì luán tíng', + '矮杆品种' => ' ǎi gǎn pǐn zhǒng', + '石膏绷带' => ' shí gāo bēng dài', + '胡行乱为' => ' hú xíng luàn wéi', + '硕果累累' => ' shuò guǒ léi léi', + '转悲为喜' => ' zhuǎn bēi wéi xǐ', + '狐唱枭和' => ' hú chàng xiāo hé', + '孤身只影' => ' gū shēn zhī yǐng', + '红绳系足' => ' hóng shéng jì zú', + '鸿篇巨著' => ' hóng piān jù zhù', + '礼坏乐崩' => ' lǐ huài yuè bēng', + '礼崩乐坏' => ' lǐ bēng yuè huài', + '礼乐崩坏' => ' lǐ yuè bēng huài', + '呼天抢地' => ' hū tiān qiāng dì', + '秀发垂肩' => ' xìu fà chuí jiān', + '鹄面鸠形' => ' hú miàn jiū xíng', + '华夏银行' => ' huá xià yín háng', + '重足屏气' => ' chóng zú bǐng qì', + '风土人情' => ' fēng tú rén qíng', + '韩国银行' => ' hán guó yín háng', + '骨牌效应' => ' gǔ pái xiào yìng', + '骆驼祥子' => ' luò tuó xiáng zǐ', + '音乐电视' => ' yīn yuè diàn shì', + '频率调制' => ' pín lù: tiáo zhì', + '颠倒是非' => ' diān dǎo shì fēi', + '颠倒过来' => ' diān dǎo guò lái', + '颠倒黑白' => ' diān dǎo hēi bái', + '风雨漂摇' => ' fēng yǔ piāo yáo', + '揣时度力' => ' chuǎi shí duó lì', + '飞来横祸' => ' fēi lái hèng huò', + '骄阳似火' => ' jiāo yáng sì huǒ', + '养尊处优' => ' yǎng zūn chǔ yōu', + '养虎为患' => ' yǎng hǔ wéi huàn', + '触物兴怀' => ' chù wù xīng huái', + '首都剧场' => ' shǒu dū jù chǎng', + '首都机场' => ' shǒu dū jī chǎng', + '触类而长' => ' chù lèi ér cháng', + '香榭丽舍' => ' xiāng xiè lì shè', + '啜英咀华' => ' chuò yīng jǔ huá', + '青堂瓦舍' => ' qīng táng wǎ shè', + '还淳反素' => ' huán chún fǎn sù', + '吃斋念佛' => ' chī zhāi niàn fó', + '百下百着' => ' bǎi xià bǎi zháo', + '充分发挥' => ' chōng fèn fā huī', + '重葩累藻' => ' chóng pā lèi zǎo', + '重门击柝' => ' chóng mén jī tuò', + '安老怀少' => ' ān lǎo huái shào', + '重迹屏气' => ' chóng jì bǐng qì', + '戳脊梁骨' => ' chuō jǐ liang gǔ', + '重规累矩' => ' chóng guī lèi jǔ', + '霸道横行' => ' bà dào héng xíng', + '北门管钥' => ' běi mén guǎn yuè', + '拜倒辕门' => ' bài dǎo yuán mén', + '白发苍苍' => ' bái fà cāng cāng', + '冲冠怒发' => ' chōng guàn nù fà', + '冲冠发怒' => ' chōng guàn fā nù', + '白发青衫' => ' bái fà qīng shān', + '白黑颠倒' => ' bái hēi diān dǎo', + '手不释卷' => ' shǒu bù shì juàn', + '扬长而去' => ' yáng cháng ér qù', + '舂容大雅' => ' chōng róng dà yá', + '表里为奸' => ' biǎo lǐ wéi jiān', + '变废为宝' => ' biàn fèi wéi bǎo', + '称心快意' => ' chèn xīn kuài yì', + '抱蔓摘瓜' => ' bào wàn zhāi guā', + '万古长新' => ' wàn gǔ cháng xīn', + '阶级成分' => ' jiē jí chéng fèn', + '随机应变' => ' suí jī yìng biàn', + '排起长队' => ' pái qǐ cháng duì', + '百中百发' => ' bǎi zhòng bǎi fā', + '排山倒海' => ' pái shān dǎo hǎi', + '抱关执钥' => ' bào guān zhí yuè', + '包皮过长' => ' bāo pí guò cháng', + '舍车保帅' => ' shě jū bǎo shuài', + '鞭长不及' => ' biān cháng bù jí', + '卑宫菲食' => ' bēi gōng fěi shí', + '白衣宰相' => ' bái yī zǎi xiàng', + '乘间伺隙' => ' chéng jiān sì xì', + '贝阙珠宫' => ' bèi què zhū gōng', + '成风尽垩' => ' chéng fēng jìn è', + '捋臂揎拳' => ' luō bì xuān quán', + '成分分析' => ' chéng fèn fēn xī', + '沙加缅度' => ' shā jiā miǎn duó', + '鞭辟向里' => ' biān bì xiàng lǐ', + '晨兴夜寐' => ' chén xīng yè mèi', + '拓扑空间' => ' tuò pū kōng jiān', + '寸长尺技' => ' cùn cháng chǐ jì', + '招人喜欢' => ' zhāo rén xǐ huan', + '冰山易倒' => ' bīng shān yì dǎo', + '屏声息气' => ' bǐng shēng xī qì', + '不相为谋' => ' bù xiāng wéi móu', + '屏退左右' => ' bǐng tuì zuǒ yòu', + '薄寒中人' => ' bó hán zhòng rén', + '长夜之饮' => ' cháng yè zhī yǐn', + '长吁短气' => ' cháng xū duǎn qì', + '不差上下' => ' bù chā shàng xià', + '倡条冶叶' => ' chāng tiáo yě yè', + '扯篷拉纤' => ' chě péng lā qiàn', + '长斋礼佛' => ' cháng zhāi lǐ fó', + '隔行扫描' => ' gé háng sǎo miáo', + '恶语中伤' => ' è yǔ zhòng shāng', + '收购要约' => ' shōu gòu yāo yuē', + '电磁感应' => ' diàn cí gǎn yìng', + '催化反应' => ' cuī huà fǎn yìng', + '电邮位置' => ' diàn yóu wèi zhi', + '摧刚为柔' => ' cuī gāng wéi róu', + '霍乱杆菌' => ' huò luàn gǎn jūn', + '超今冠古' => ' chāo jīn guàn gǔ', + '挑灯拨火' => ' tiǎo dēng bō huǒ', + '拐弯抹角' => ' guǎi wān mò jiǎo', + '长短不一' => ' cháng duǎn bù yī', + '长舌之妇' => ' cháng shé zhī fù', + '找不着北' => ' zhǎo bu zháo běi', + '惨绿少年' => ' cǎn lǜ shào nián', + '苍劲有力' => ' cāng jìng yǒu lì', + '长驱直进' => ' cháng qū zhí jìn', + '材高知深' => ' cái gāo zhì shēn', + '长驱深入' => ' cháng qū shēn rù', + '抽丝剥茧' => ' chōu sī bāo jiǎn', + '长此以往' => ' cháng cǐ yǐ wǎng', + '长歌当哭' => ' cháng gē dàng kū', + '宾主尽欢' => ' bīn zhǔ jìn huān', + '长戟高门' => ' cháng jǐ gāo mén', + '长计远虑' => ' cháng jì yuǎn lǜ', + '长久之计' => ' cháng jiǔ zhī jì', + '层台累榭' => ' céng tái lěi xiè', + '表面处理' => ' biǎo miàn chǔ lǐ', + '材薄质衰' => ' cái bó zhì shuāi', + '畅所欲为' => ' chàng suǒ yù wéi', + '别创一格' => ' bié chuàng yí gé', + '趁水和泥' => ' chèn shuǐ huò ní', + '还淳反古' => ' huán chún fǎn gǔ', + '回天运斗' => ' huí tiān yùn dǒu', + '调味肉汁' => ' tiáo wèi ròu zhī', + '夹心饼干' => ' jiā xīn bǐng gān', + '简能而任' => ' jiǎn néng ér rèn', + '见哭兴悲' => ' jiàn kū xīng bēi', + '武装分子' => ' wǔ zhuāng fèn zǐ', + '犯罪行为' => ' fàn zuì xíng wéi', + '正负电子' => ' zhèng fù diàn zǐ', + '正确处理' => ' zhèng què chǔ lǐ', + '俭不中礼' => ' jiǎn bù zhòng lǐ', + '赍粮藉寇' => ' jī liáng jiè kòu', + '正月初一' => ' zhēng yuè chū yī', + '槛花笼鹤' => ' jiàn huā lóng hè', + '现代音乐' => ' xiàn dài yīn yuè', + '价格行情' => ' jià gé háng qíng', + '击中要害' => ' jī zhòng yào hài', + '正人君子' => ' zhèng rén jūn zǐ', + '积微成著' => ' jī wēi chéng zhù', + '甲壳动物' => ' jiǎ qiào dòng wù', + '好整以暇' => ' hào zhěng yǐ xiá', + '宽大为怀' => ' kuān dà wéi huái', + '长眠不起' => ' cháng mián bù qǐ', + '歃血为盟' => ' shà xuè wéi méng', + '见义当为' => ' jiàn yì dāng wéi', + '缓发中子' => ' huǎn fā zhōng zǐ', + '当行出色' => ' dāng háng chū sè', + '流行音乐' => ' liú xíng yīn yuè', + '目挑心招' => ' mù tiǎo xīn zhāo', + '牢靠妥当' => ' láo kào tuǒ dàng', + '槟榔西施' => ' bīng lang xī shī', + '机关算尽' => ' jī guān suàn jìn', + '威化饼干' => ' wēi huà bǐng gān', + '威慑力量' => ' wēi shè lì liang', + '饥冻交切' => ' jī dòng jiāo qiē', + '疾风劲草' => ' jí fēng jìng cǎo', + '横行霸道' => ' héng xíng bà dào', + '发言中肯' => ' fā yán zhòng kěn', + '机关用尽' => ' jī guān yòng jìn', + '百废待兴' => ' bǎi fèi dài xīng', + '百发百中' => ' bǎi fā bǎi zhòng', + '百般刁难' => ' bǎi bān diāo nàn', + '火尽灰冷' => ' huǒ jìn huī lěng', + '婚姻调解' => ' hūn yīn tiáo jiě', + '尽善尽美' => ' jìn shàn jìn měi', + '霍尔效应' => ' huò ěr xiào yìng', + '购销合同' => ' gòu xiāo hé tong', + '聚变反应' => ' jù biàn fǎn yìng', + '奉为圭臬' => ' fèng wéi guī niè', + '柏林围墙' => ' bó lín wéi qiáng', + '翘首以待' => ' qiáo shóu yǐ dài', + '绷巴吊拷' => ' bèng bā diào kǎo', + '兴业银行' => ' xīng yè yín háng', + '旧地重游' => ' jiù dì chóng yóu', + '公共积累' => ' gōng gòng jī lěi', + '将伯之助' => ' qiāng bó zhī zhù', + '鬼魅伎俩' => ' guǐ mèi jì liǎng', + '鼓乐喧天' => ' gǔ yuè xuān tiān', + '自力更生' => ' zì lì gēng shēng', + '弓折刀尽' => ' gōng zhé dāo jìn', + '更弦易辙' => ' gēng xián yì zhé', + '东亚银行' => ' dōng yà yín háng', + '罪行累累' => ' zuì xíng lěi lěi', + '莘莘学子' => ' shēn shēn xué zǐ', + '纶巾羽扇' => ' guān jīn yǔ shàn', + '听墙根儿' => ' tīng qiáng gēn r', + '脱不了身' => ' tuō bù liǎo shēn', + '背景音乐' => ' bèi jǐng yīn yuè', + '小两口儿' => ' xiǎo liǎng kǒu r', + '绷扒吊拷' => ' bēng bā diào kǎo', + '老少咸宜' => ' lǎo shào xián yí', + '紧急应变' => ' jǐn jí yìng biàn', + '兴师问罪' => ' xīng shī wèn zuì', + '国难当头' => ' guó nàn dāng tóu', + '柔情似水' => ' róu qíng sì shuǐ', + '公子王孙' => ' gōng zǐ wáng sūn', + '小缸缸儿' => ' xiǎo gāng gang r', + '贡禹弹冠' => ' gòng yǔ tán guān', + '草草了事' => ' cǎo cǎo liǎo shì', + '良家女子' => ' liáng jiā nǔ: zǐ', + '兴高彩烈' => ' xīng gāo cǎi liè', + '花不棱登' => ' huā bù lēng dēng', + '缝衣工人' => ' féng yī gōng rén', + '经济困境' => ' jīng jì kùn jìng', + '冠山戴粒' => ' guàn shān dài lì', + '专业知识' => ' zhuān yè zhī shi', + '英语教学' => ' yīng yǔ jiāo xué', + '兴隆台区' => ' xīng lóng tái qū', + '翘居群首' => ' qiáo jū qún shǒu', + '绕梁三日' => ' rǎo liáng sān rì', + '翘足引领' => ' qiáo zú yǐn lǐng', + '过从甚密' => ' guò cóng shèn mì', + '沦没丧亡' => ' lún mò sàng wáng', + '矫国更俗' => ' jiǎo guó gēng sú', + '回山倒海' => ' huí shān dǎo hǎi', + '桁杨刀锯' => ' háng yáng dāo jù', + '好为事端' => ' hào wéi shì duān', + '红寡妇鸟' => ' hóng guǎ fu niǎo', + '毫不相干' => ' háo bù xiāng gān', + '行伍出身' => ' háng wǔ chū shēn', + '审度时势' => ' shěn duó shí shì', + '红颜薄命' => ' hóng yán bó mìng', + '累加总数' => ' lěi jiā zǒng shù', + '审时度势' => ' shěn shí duó shì', + '毫发不爽' => ' háo fà bù shuǎng', + '浩气长存' => ' hào qì cháng cún', + '科教兴国' => ' kē jiào xīng guó', + '好勇斗狠' => ' hào yǒng dòu hěn', + '鹤短凫长' => ' hè duǎn fú cháng', + '横灾飞祸' => ' hèng zāi fēi huò', + '空气调节' => ' kōng qì tiáo jié', + '棺材瓤子' => ' guān cai ráng zi', + '横行逆施' => ' héng xíng nì shī', + '完全懂得' => ' wán quán dǒng de', + '穷于应付' => ' qióng yú yìng fù', + '实际应用' => ' shí jì yìng yòng', + '寥寥可数' => ' liáo liáo kě shǔ', + '鹤长凫短' => ' hè cháng fú duǎn', + '众矢之的' => ' zhòng shǐ zhī dì', + '相夫教子' => ' xiàng fū jiào zǐ', + '相差不多' => ' xiāng chà bu duō', + '黄绵袄子' => ' huáng mián ǎo zǐ', + '相机而动' => ' xiàng jī ér dòng', + '还淳返朴' => ' huán chún fǎn pǔ', + '相机而行' => ' xiàng jī ér xíng', + '眼泪横流' => ' yǎn lèi hèng líu', + '眼见为实' => ' yǎn jiàn wéi shí', + '还年驻色' => ' huán nián zhù sè', + '察察为明' => ' chá chá wéi míng', + '瞬发中子' => ' shùn fā zhōng zǐ', + '患难与共' => ' huàn nàn yǔ gòng', + '换斗移星' => ' huàn dǒu yí xīng', + '黄冠野服' => ' huáng guàn yě fú', + '横征苛役' => ' hèng zhēng kē yì', + '稀里光当' => ' xī li guāng dāng', + '桴鼓相应' => ' fú gǔ xiāng yìng', + '好生之德' => ' hào shēng zhī dé', + '寓意深长' => ' yù yì shēn cháng', + '站不住脚' => ' zhàn bu zhù jiǎo', + '横科暴敛' => ' hèng kē bào liǎn', + '液晶显示' => ' yè jīng xiǎn shì', + '法国长棍' => ' fǎ guó cháng gùn', + '热岛效应' => ' rè dǎo xiào yìng', + '死海经卷' => ' sǐ hǎi jīng juàn', + '燕雀处堂' => ' yàn què chǔ táng', + '为人师表' => ' wéi rén shī biǎo', + '历尽沧桑' => ' lì jìn cāng sāng', + '测量工具' => ' cè liáng gōng jù', + '深恶痛绝' => ' shēn wù tòng jué', + '夹脚拖鞋' => ' jiá jiǎo tuō xié', + '泰山北斗' => ' tài shān běi dǒu', + '煎炸食品' => ' jiān zhá shí pǐn', + '活神仙似' => ' huó shén xiān sì', + '没完没了' => ' méi wán méi liǎo', + '派拉蒙影' => ' pài lā měng yǐng', + '胶柱调瑟' => ' jiāo zhù tiáo sè', + '深更半夜' => ' shēn gēng bàn yè', + '矫情干誉' => ' jiǎo qíng gān yù', + '海盗行为' => ' hǎi dào xíng wéi', + '角巾东路' => ' jiǎo jīn dōng lù', + '消息来源' => ' xiāo xi lái yuán', + '烟熏火燎' => ' yān xūn huǒ liǎo', + '壳牌公司' => ' qiào pái gōng sī', + '哼哈二将' => ' hēng hā èr jiàng', + '树碑立传' => ' shù bēi lì zhuàn', + '等差数列' => ' děng chā shù liè', + '简单地说' => ' jiǎn dān de shuō', + '横倒竖歪' => ' héng dǎo shù wāi', + '黑白颠倒' => ' hēi bái diān dǎo', + '河清云庆' => ' hé qīng yún qìng', + '家常豆腐' => ' jiā cháng dòu fu', + '横祸飞灾' => ' hèng huò fēi zāi', + '绞尽脑汁' => ' jiǎo jìn nǎo zhī', + '毁舟为杕' => ' huǐ zhōu wéi duò', + '游说团体' => ' yóu shuì tuán tǐ', + '烈火干柴' => ' liè huǒ gān chái', + '浑身解数' => ' hún shēn xiè shù', + '水底相机' => ' shuǐ dǐ xiàng jī', + '溢出效应' => ' yì chū xiào yìng', + '满口脏话' => ' mǎn kǒu zāng huà', + '气冲牛斗' => ' qì chōng niú dǒu', + '漫漫长夜' => ' màn màn cháng yè', + '民间音乐' => ' mín jiān yīn yuè', + '较德焯勤' => ' jiào dé zhuō qín', + '炎黄子孙' => ' yán huáng zǐ sūn', + '词优效应' => ' cí yōu xiào yìng', + '春深似海' => ' chūn shēn sì hǎi', + '电子文档' => ' diàn zǐ wén dàng', + '豁然开朗' => ' huò rán kāi lǎng', + '一朝之患' => ' yī zhāo zhī huàn', + '恬不为怪' => ' tián bù wéi guài', + '叹为观止' => ' tàn wéi guān zhǐ', + '鸾鹄在庭' => ' luán hú zài tíng', + '发人深省' => ' fā rén shēn xǐng', + '长度单位' => ' cháng dù dān wèi', + '铜管乐器' => ' tóng guǎn yuè qì', + '钉头磷磷' => ' ding tou lin lin', + '鸾孤凤只' => ' luán gū fèng zhī', + '军团杆菌' => ' jūn tuán gǎn jūn', + '丢车保帅' => ' diū jū bǎo shuài', + '反躬自省' => ' fǎn gōng zì xǐng', + '地狱变相' => ' dì yù biàn xiàng', + '金山屯区' => ' jīn shān zhūn qū', + '从长计议' => ' cóng cháng jì yì', + '庚子国变' => ' gēng zǐ guó biàn', + '地方风味' => ' dì fāng fēng wèi', + '过敏反应' => ' guò mǐn fǎn yìng', + '灯尽油干' => ' dēng jìn yóu gàn', + '奉为至宝' => ' fèng wéi zhì bǎo', + '长治久安' => ' cháng zhì jiǔ ān', + '鸾鹄停峙' => ' luán hú tíng zhì', + '绿林强盗' => ' lù lín qiáng dào', + '有为有守' => ' yǒu wéi yǒu shǒu', + '返朴还淳' => ' fǎn pǔ huán chún', + '剔抽秃揣' => ' tī chōu tū chuǎi', + '陆相沉积' => ' lù xiàng chén jī', + '乱臣贼子' => ' luàn chén zéi zǐ', + '剔蝎撩蜂' => ' tī xiē liáo fēng', + '反应迟钝' => ' fǎn yìng chí dùn', + '返朴还真' => ' fǎn pǔ huán zhēn', + '刁钻促狭' => ' diāo zuàn cù xiá', + '新兴产业' => ' xīn xīng chǎn yè', + '强直自遂' => ' qiáng zhí zì suí', + '可共患难' => ' kě gòng huàn nàn', + '发怒冲冠' => ' fà nù chōng guān', + '钝学累功' => ' dùn xué lěi gōng', + '方兴未艾' => ' fāng xīng wèi ài', + '刁斗森严' => ' diāo dǒu sēn yán', + '似懂非懂' => ' sì dǒng fēi dǒng', + '连篇累牍' => ' lián piān lěi dú', + '眠花藉柳' => ' mián huā jiè liǔ', + '雕肝琢膂' => ' diāo gān zhuó lǚ', + '一哄而上' => ' yì hōng ér shàng', + '方兴未已' => ' fāng xīng wèi yǐ', + '靡然从风' => ' mǐ rán cóng fēng', + '通讯行业' => ' tōng xùn háng yè', + '谦谦君子' => ' qiān qiān jūn zǐ', + '阿党相为' => ' ē dǎng xiāng wéi', + '慢性咽炎' => ' màn xìng yān yán', + '颠倒干坤' => ' diān dǎo gàn kūn', + '新都桥镇' => ' xīn dū qiáo zhèn', + '泛应曲当' => ' fàn yīng qǔ dāng', + '铤而走险' => ' tǐng ér zǒu xiǎn', + '发怒穿冠' => ' fà nù chuān guān', + '鸾停鹄峙' => ' luán tíng hú zhì', + '儿女情长' => ' ér nǚ qíng cháng', + '伏虎降龙' => ' fú hǔ xiáng lóng', + '天差地远' => ' tiān chā dì yuǎn', + '以守为攻' => ' yǐ shǒu wéi gōng', + '得心应手' => ' dé xīn yìng shǒu', + '巧发奇中' => ' qiǎo fā qí zhòng', + '率尔操觚' => ' shuài ěr cāo gū', + '转危为安' => ' zhuǎn wēi wéi ān', + '儿女成行' => ' ér nǚ chéng háng', + '裸裎袒裼' => ' luǒ chéng tǎn xī', + '单方恐吓' => ' dān fāng kǒng hè', + '意义深长' => ' yì yì shēn cháng', + '长夜漫漫' => ' cháng yè màn màn', + '强死赖活' => ' qiǎng sǐ lài huó', + '干柴烈火' => ' gān chái liè huǒ', + '行为准则' => ' xíng wéi zhǔn zé', + '缟纻之交' => ' gāo zhù zhī jiāo', + '动画片儿' => ' dòng huà piān er', + '著称于世' => ' zhù chēng yú shì', + '朝思暮想' => ' zhāo sī mù xiǎng', + '各有所长' => ' gè yǒu suǒ cháng', + '衣绣昼行' => ' yì xiù zhòu xíng', + '朱云折槛' => ' zhū yún shé jiàn', + '朝令夕改' => ' zhāo lìng xī gǎi', + '差动齿轮' => ' chā dòng chǐ lún', + '叶公好龙' => ' yè gōng hào lóng', + '军事力量' => ' jūn shì lì liang', + '蝴蝶效应' => ' hú dié xiào yìng', + '差强人意' => ' chā qiáng rén yì', + '葛莱美奖' => ' gě lái měi jiǎng', + '见微知著' => ' jiàn wēi zhī zhù', + '竭尽所能' => ' jié jìn suǒ néng', + '凫短鹤长' => ' fú duǎn hè cháng', + '强凫变鹤' => ' qiǎng fú biàn hè', + '望而兴叹' => ' wàng ér xīng tàn', + '佛眼相看' => ' fó yǎn xiāng kàn', + '佛性禅心' => ' fó xìng chán xīn', + '血债累累' => ' xuè zhài lěi lěi', + '缝衣浅带' => ' féng yī qiǎn dài', + '绷爬吊拷' => ' bēng pá diào kǎo', + '凤子龙孙' => ' fèng zǐ lóng sūn', + '凤只鸾孤' => ' fèng zhī luán gū', + '风云之志' => ' fēng yún zhī zhì', + '切中时弊' => ' qiè zhòng shí bì', + '朋比为奸' => ' péng bǐ wéi jiān', + '叱吒风云' => ' chì zhà fēng yún', + '未竟之志' => ' wèi jìng zhī zhì', + '天王老子' => ' tiān wáng lǎo zǐ', + '强文假醋' => ' qiǎng wén jiǎ cù', + '薄养厚葬' => ' bó yǎng hòu zàng', + '单眼相机' => ' dān yǎn xiàng jī', + '一天星斗' => ' yī tiān xīng dǒu', + '崭露头角' => ' zhǎn lù tóu jiǎo', + '杠杆原理' => ' gàng gǎn yuán lǐ', + '抢地呼天' => ' qiāng dì hū tiān', + '朝鲜八道' => ' cháo xiǎn bā dào', + '朝鲜日报' => ' cháo xiǎn rì bào', + '以慎为键' => ' yǐ shèn wéi jiàn', + '斗筲之材' => ' dǒu shāo zhī cái', + '弹尽援绝' => ' dàn jìn yuán jué', + '量化逻辑' => ' liàng huà luó ji', + '卖文为生' => ' mài wén wéi shēn', + '颠唇簸嘴' => ' diān chún bò zuǐ', + '量入为出' => ' liàng rù wéi chū', + '重蹈覆辙' => ' chóng dǎo fù zhé', + '血流漂杵' => ' xuè liú piāo chǔ', + '行家里手' => ' háng jiā lǐ shǒu', + '东横西倒' => ' dōng héng xī dǎo', + '朝饔夕飧' => ' zhāo yōng xī sūn', + '高情逸兴' => ' gāo qíng yì xīng', + '告老还家' => ' gào lǎo huán jiā', + '处堂燕雀' => ' chǔ táng yàn què', + '游说集团' => ' yóu shuì jí tuán', + '膏唇贩舌' => ' gào chún fàn shé', + '对薄公堂' => ' duì bù gōng táng', + '阴错阳差' => ' yīn cuò yáng chā', + '强识博闻' => ' qiǎng shí bó wén', + '朝鲜核谈' => ' cháo xiǎn hé tán', + '强聒不舍' => ' qiǎng guō bù shě', + '田父之功' => ' tián fǔ zhī gōng', + '以攻为守' => ' yǐ gōng wéi shǒu', + '倒执手版' => ' dǎo zhí shǒu bǎn', + '任人唯贤' => ' rèn rén wéi xián', + '亲生子女' => ' qīn shēng zǐ nǔ:', + '倒冠落佩' => ' dǎo guān luò pèi', + '数典忘祖' => ' shǔ diǎn wàng zǔ', + '有两下子' => ' yǒu liǎng xià zǐ', + '酌情处理' => ' zhuó qíng chǔ lǐ', + '仰屋兴叹' => ' yǎng wū xīng tàn', + '倒持手板' => ' dǎo chí shǒu bǎn', + '间隔摄影' => ' jiàn gé shè yǐng', + '防毒斗篷' => ' fáng dú dǒu péng', + '一口两匙' => ' yī kǒu liǎng chí', + '长途网路' => ' cháng tú wǎng lù', + '解铃系铃' => ' jiě líng jì líng', + '搴旗取将' => ' qiān qí qǔ jiàng', + '斗酒百篇' => ' dǒu jiǔ bǎi piān', + '道傍之筑' => ' dào bàng zhī zhù', + '一长二短' => ' yī cháng èr duǎn', + '短见薄识' => ' duǎn jiàn bó shí', + '非意相干' => ' fēi yì xiāng gān', + '除旧更新' => ' chú jiù gēng xīn', + '重新开机' => ' chóng xīn kāi jī', + '重历旧游' => ' chóng lì jìu yóu', + '亲朋好友' => ' qīn péng háo you', + '千载一逢' => ' qiān zǎi yī féng', + '倒廪倾囷' => ' dǎo lǐn qīng qūn', + '勉强及格' => ' miǎn qiǎng jí gé', + '道尽途穷' => ' dào jìn tú qióng', + '飞灾横祸' => ' fēi zāi hèng huò', + '重复语境' => ' chóng fù yǔ jìng', + '酩酊大醉' => ' mǐng dǐng dà zuì', + '认知失调' => ' rèn zhī shī tiáo', + '弧长参数' => ' hú cháng cān shù', + '单反相机' => ' dān fǎn xiàng jī', + '天造草昧' => ' tiān zào cǎo mèi', + '间接选举' => ' jiàn jiē xuǎn jǔ', + '都中纸贵' => ' dū zhōng zhǐ guì', + '词频效应' => ' cí pín xiào yìng', + '弦鸣乐器' => ' xián míng yuè qì', + '斗折蛇行' => ' dǒu zhé shé xíng', + '数九寒天' => ' shǔ jiǔ hán tiān', + '重操旧业' => ' chóng cāo jiù yè', + '天之骄子' => ' tiān zhī jiāo zǐ', + '数不胜数' => ' shǔ bù shèng shǔ', + '钻头夹盘' => ' zuàn tóu jiá pán', + '天下为家' => ' tiān xià wéi jiā', + '讨价还价' => ' tǎo jià huán jià', + '调嘴学舌' => ' tiáo zuǐ xué shé', + '断发文身' => ' duàn fà wén shēn', + '猫鼠同处' => ' māo shǔ tóng chǔ', + '都铎王朝' => ' dū duó wáng cháo', + '降龙伏虎' => ' xiáng lóng fú hǔ', + '早期效应' => ' zǎo qī xiào yìng', + '移动平台' => ' yí dòng píng tái', + '似水年华' => ' sì shuǐ nián huá', + '似笑非笑' => ' sì xiào fēi xiào', + '倒街卧巷' => ' dǎo jiē wò xiàng', + '谁人乐队' => ' shéi rén yuè duì', + '鼎鼐调和' => ' dǐng nai tiáo hé', + '钻头卡盘' => ' zuàn tóu qiǎ pán', + '一了百当' => ' yī liǎo bǎi dàng', + '长途话费' => ' cháng tú huà fèi', + '斗筲之人' => ' dǒu shāo zhī rén', + '心广体胖' => ' xīn guǎng tǐ pán', + '重温旧业' => ' chóng wēn jiù yè', + '见义勇为' => ' jiàn yì yǒng wéi', + '彰善瘅恶' => ' zhāng shàn dàn è', + '电子产品' => ' diàn zǐ chǎn pǐn', + '风流蕴藉' => ' fēng liú yùn jiè', + '年少无知' => ' nián shào wú zhī', + '盗嫂受金' => ' dào sǎo shòu jīn', + '费尽周折' => ' fèi jìn zhōu zhé', + '点石为金' => ' diǎn shí wéi jīn', + '阴差阳错' => ' yīn chā yáng cuò', + '早生贵子' => ' zǎo shēng guì zǐ', + '亲子鉴定' => ' qīn zǐ jiàn dìng', + '面南背北' => ' miàn nán bèi běi', + '重提旧事' => ' chóng tí jìu shì', + '断线鹞子' => ' duàn xiàn yào zǐ', + '心拙口夯' => ' xīn zhuō kǒu bèn', + '锋镝余生' => ' fēng dí yú shēng', + '弹射座舱' => ' tán shè zuò cāng', + '都江堰市' => ' dū jiāng yàn shì', + '毛遂堕井' => ' máo suí duò jǐng', + '调理阴阳' => ' tiáo lǐ yīn yáng', + '一长一短' => ' yī cháng yī duǎn', + '弹指之间' => ' tán zhǐ zhī jiān', + '视微知着' => ' shì wēi zhī zhuó', + '重睹天日' => ' chóng dǔ tiān rì', + '堆垛机' => ' duī duò jī', + '度假者' => ' dù jià zhě', + '西门町' => ' xī mén dīng', + '脑瓢儿' => ' nǎo piáo r', + '乌什县' => ' wū shí xiàn', + '眼不见' => ' yǎn bú jiàn', + '脑瓜子' => ' nǎo guā zǐ', + '处子秀' => ' chǔ zǐ xìu', + '伪君子' => ' wěi jūn zǐ', + '脊梁骨' => ' jǐ liáng gǔ', + '四公子' => ' sì gōng zǐ', + '尽人事' => ' jìn rén shì', + '腿腕子' => ' tuǐ wàn zǐ', + '多得是' => ' duō de shì', + '瓦楞子' => ' wǎ léng zǐ', + '遛弯儿' => ' liù wān ér', + '瓜子脸' => ' guā zǐ liǎn', + '内切球' => ' nèi qiē qíu', + '戏园子' => ' xì yuán zǐ', + '狗仔式' => ' gǒu zǎi shì', + '药方儿' => ' yào fāng r', + '择不开' => ' zhái bù kāi', + '药师佛' => ' yào shī fó', + '三拗汤' => ' sān ào tāng', + '曾都区' => ' zēng dū qū', + '药水儿' => ' yào shuǐ r', + '延误费' => ' yán wu fèi', + '看家戏' => ' kān jiā xì', + '再处理' => ' zài chǔ lǐ', + '塞尔南' => ' sài ěr nán', + '脖颈子' => ' bó gěng zi', + '戏馆子' => ' xì guǎn zǐ', + '刨笔刀' => ' bào bǐ dāo', + '快板儿' => ' kuài bǎn r', + '喜剧片' => ' xǐ jù piān', + '曲别针' => ' qǔ bié zhēn', + '反间计' => ' fǎn jiàn jì', + '君子国' => ' jūn zǐ guó', + '弥勒县' => ' mí lè xiàn', + '坤角儿' => ' kūn jué ér', + '薄伽丘' => ' bó jiā qīu', + '避难所' => ' bì nàn suǒ', + '坏包儿' => ' huài bāo r', + '可的松' => ' kě dì sōng', + '俱舍宗' => ' jù shè zōng', + '空白符' => ' kòng bái fú', + '颅测量' => ' lú cè liáng', + '拿不动' => ' ná bu dòng', + '会计科' => ' kuài jì kē', + '弹拨乐' => ' tán bō yuè', + '倒好儿' => ' dǎo hǎo ér', + '迫击炮' => ' pǎi jī pào', + '大舌头' => ' dà shé tou', + '鼻粘膜' => ' bí nián mó', + '微电子' => ' wēi diàn zǐ', + '遇难者' => ' yù nàn zhě', + '洛子峰' => ' luò zǐ fēng', + '鼻咽炎' => ' bí yān yán', + '保不住' => ' bǎo bú zhù', + '曲沃县' => ' qǔ wò xiàn', + '梭子蟹' => ' suō zǐ xiè', + '分子论' => ' fēn zǐ lùn', + '浪卡子' => ' làng kǎ zǐ', + '松巴哇' => ' sōng bā wā', + '前奏曲' => ' qián zòu qǔ', + '锁子甲' => ' suǒ zǐ jiǎ', + '都兰县' => ' dū lán xiàn', + '弹劾权' => ' tán hé quán', + '忍得住' => ' rěn de zhù', + '过家伙' => ' guō jiā huo', + '划不来' => ' huá bù lái', + '这下子' => ' zhè xià zǐ', + '碎嘴子' => ' suì zuǐ zǐ', + '避风头' => ' bì fēng tou', + '水泡子' => ' shuǐ pāo zi', + '兴安区' => ' xīng ān qū', + '舔屁股' => ' tiǎn pì gu', + '过不下' => ' guò bu xià', + '恐吓信' => ' kǒng hè xìn', + '大兴区' => ' dà xīng qū', + '弹性体' => ' tán xìng tǐ', + '知识化' => ' zhī shi huà', + '随大溜' => ' suí dà liù', + '过得去' => ' guò děi qù', + '西藏人' => ' xī zàng rén', + '划得来' => ' huá de lái', + '大轴戏' => ' dà zhòu xì', + '说不到' => ' shuō bú dào', + '托门子' => ' tuō mén zǐ', + '脖颈儿' => ' bó gěng ér', + '脊髓炎' => ' jǐ suǐ yán', + '傍家儿' => ' bàng jiā r', + '多任务' => ' duō rèn wu', + '会计课' => ' kuài jì kè', + '试手儿' => ' shì shǒu r', + '都更案' => ' dū gēng àn', + '了不得' => ' liǎo bù dé', + '武曲星' => ' wǔ qǔ xīng', + '填塞物' => ' tián sè wù', + '都柏林' => ' dōu bó lín', + '处女作' => ' chǔ nǚ zuò', + '压轴子' => ' yā zhòu zǐ', + '处女座' => ' chǔ nǚ zuò', + '剃发令' => ' tì fà lìng', + '无名子' => ' wú míng zǐ', + '傀儡戏' => ' kuǐ lěi xì', + '逗闷子' => ' dòu mèn zǐ', + '佛甲草' => ' fó jiǎ cǎo', + '排子车' => ' pǎi zǐ chē', + '近似解' => ' jìn sì jiě', + '练习曲' => ' liàn xí qǔ', + '这阵儿' => ' zhè zhèn r', + '这边儿' => ' zhè biān r', + '九曲桥' => ' jiǔ qǔ qiáo', + '老师傅' => ' lǎo shī fū', + '都安县' => ' dū an xiàn', + '近似值' => ' jìn sì zhí', + '部分值' => ' bù fèn zhí', + '脯氨酸' => ' fǔ ān suān', + '都匀市' => ' dū yún shì', + '指事字' => ' zhǐ shì zì', + '怪物似' => ' guài wù sì', + '亚粘土' => ' yà nián tǔ', + '啃骨头' => ' kěn gú tou', + '避难权' => ' bì nàn quán', + '度假村' => ' dù jià cūn', + '胡涂虫' => ' hú tu chóng', + '空心儿' => ' kòng xīn r', + '油炸机' => ' yóu zhá jī', + '补给船' => ' bǔ jǐ chuán', + '了不起' => ' liǎo bù qǐ', + '戳份儿' => ' chuō fèn r', + '趵突泉' => ' bō tū quán', + '有为法' => ' yǒu wéi fǎ', + '栖霞市' => ' xī xiá shì', + '北碚区' => ' běi bèi qū', + '煤黑子' => ' méi hēi zǐ', + '窝囊气' => ' wō nāng qì', + '北边儿' => ' běi biān r', + '窍门儿' => ' qiào mén r', + '策勒县' => ' cè lè xiàn', + '与会者' => ' yù huì zhě', + '佛香阁' => ' fó xiāng gé', + '马钱子' => ' mǎ qián zǐ', + '料头儿' => ' liào tóu r', + '干燥器' => ' gān zào qì', + '量热器' => ' liáng rè qì', + '红模子' => ' hóng mú zǐ', + '激将法' => ' jī jiàng fǎ', + '干燥炉' => ' gān zào lú', + '歌片儿' => ' gē piān er', + '套衫儿' => ' tào shān r', + '出门子' => ' chū mén zǐ', + '毛丫头' => ' máo yā tou', + '出月子' => ' chū yuè zǐ', + '一刀切' => ' yī dāo qiē', + '枯萎病' => ' kū wěi bìng', + '柞蚕丝' => ' zuò cán sī', + '一个样' => ' yī ge yàng', + '作曲者' => ' zuò qǔ zhě', + '排叉儿' => ' pái chà ér', + '懒骨头' => ' lǎn gǔ tou', + '有会子' => ' yǒu huì zǐ', + '卷发器' => ' juǎn fà qì', + '踝子骨' => ' huái zǐ gǔ', + '混球儿' => ' hún qiú ér', + '补给线' => ' bú jǐ xiàn', + '子系统' => ' zǐ xì tǒng', + '高丽纸' => ' gāo lí zhǐ', + '摇滚乐' => ' yáo gǔn yuè', + '子午莲' => ' zǐ wǔ lián', + '炮筒子' => ' pào tǒng zǐ', + '包园儿' => ' bāo yuán r', + '乔答摩' => ' qiáo dā mó', + '套马杆' => ' tào mǎ gǎn', + '备不住' => ' bèi bú zhù', + '二愣子' => ' èr lèng zǐ', + '暗适应' => ' àn shì yìng', + '处理品' => ' chǔ lǐ pǐn', + '斗门区' => ' dǒu mén qū', + '旋木雀' => ' xuàn mù què', + '打不通' => ' dǎ bu tōng', + '畜牧场' => ' xù mù chǎng', + '南边儿' => ' nán bian r', + '吴兴区' => ' wú xīng qū', + '贾似道' => ' jiǎ sì dào', + '石榴子' => ' shí liu zǐ', + '碌曲县' => ' lù qǔ xiàn', + '碎块儿' => ' suì kuài r', + '打呵欠' => ' dǎ hē qiàn', + '干旱土' => ' gān hàn tǔ', + '喝倒彩' => ' hè dào cǎi', + '干梅子' => ' gān méi zi', + '知识库' => ' zhī shi kù', + '脏乎乎' => ' zāng hū hū', + '南海子' => ' nán hǎi zǐ', + '拌和机' => ' bàn huò jī', + '喀什市' => ' kā shí shì', + '小菜儿' => ' xiǎo cài r', + '眼底下' => ' yǎn dǐ xia', + '增压器' => ' zēng yà qì', + '增压机' => ' zēng yà jī', + '增压比' => ' zēng yà bǐ', + '打擂台' => ' dǎ lèi tái', + '少不得' => ' shǎo bu dé', + '狗骨头' => ' gǒu gú tou', + '氨哮素' => ' ān xiào sù', + '石头记' => ' shí tou jì', + '快点儿' => ' kuài diǎn r', + '亚原子' => ' yà yuán zǐ', + '不到家' => ' bú dào jiā', + '脊椎骨' => ' jǐ zhuī gǔ', + '捧角儿' => ' pěng jué r', + '锄头雨' => ' chú tou yǔ', + '应答器' => ' yìng dá qì', + '叫哥哥' => ' jiào gē ge', + '五斗柜' => ' wǔ dǒu guì', + '丑婆子' => ' chǒu pó zǐ', + '背不住' => ' bèi bú zhù', + '包干儿' => ' bāo gān ér', + '节骨眼' => ' jiē gǔ yǎn', + '奔头儿' => ' bèn tou er', + '云头儿' => ' yún tou er', + '粘合剂' => ' nián hé jì', + '简帖儿' => ' jiǎn tiě r', + '背带裤' => ' bēi dài kù', + '丰子恺' => ' fēng zǐ kǎi', + '反诘问' => ' fǎn jié wèn', + '混名儿' => ' hùn míng r', + '漂洗机' => ' piǎo xǐ jī', + '粘乎乎' => ' nián hū hū', + '与会国' => ' yù huì guó', + '女公子' => ' nǚ gōng zǐ', + '出主意' => ' chū zhǔ yi', + '拦不住' => ' lán bú zhù', + '让步地' => ' ràng bù de', + '河曲县' => ' hé qǔ xiàn', + '老大难' => ' lǎo dà nàn', + '配给品' => ' pèi jǐ pǐn', + '有道理' => ' yǒu dào li', + '有边儿' => ' yǒu biān r', + '要样儿' => ' yào yàng r', + '扩散剂' => ' kuò sǎn jì', + '童子鸡' => ' tóng zǐ jī', + '调和漆' => ' tiáo hé qī', + '老鸨子' => ' lǎo bǎo zǐ', + '前边儿' => ' qián bian r', + '分子式' => ' fèn zǐ shì', + '贺子珍' => ' hè zǐ zhēn', + '空壳子' => ' kōng ké zǐ', + '文曲星' => ' wén qǔ xīng', + '挑头儿' => ' tiǎo tóu r', + '大不了' => ' dà bù liǎo', + '倒计时' => ' dǎo jì shí', + '徐熙媛' => ' xú xī yuán', + '责任人' => ' zé rèn rén', + '调色剂' => ' tiáo sè jì', + '塔什干' => ' tǎ shí gàn', + '螺丝钻' => ' luó sī zuàn', + '调速器' => ' tiáo sù qì', + '嘴把式' => ' zuǐ bǎ shi', + '有益处' => ' yǒu yì chu', + '配给制' => ' pèi jǐ zhì', + '王世子' => ' wáng shì zǐ', + '甚至于' => ' shèn zhì yú', + '补给站' => ' bǔ jǐ zhàn', + '杜松子' => ' dù sōng zǐ', + '克耶邦' => ' kè yē bāng', + '被誉为' => ' bèi yù wéi', + '袖筒儿' => ' xìu tǒng r', + '独不见' => ' dú bú jiàn', + '压轴戏' => ' yā zhòu xì', + '说得来' => ' shuō de lái', + '做头发' => ' zuò tóu fà', + '褪套儿' => ' tùn tào ér', + '要不是' => ' yào bú shì', + '五斗橱' => ' wǔ dǒu chú', + '蛋卷儿' => ' dàn juǎn r', + '八爪鱼' => ' bā zhuǎ yú', + '反电子' => ' fǎn diàn zǐ', + '泊头市' => ' bó tóu shì', + '弹子锁' => ' dàn zǐ suǒ', + '月头儿' => ' yuè tou er', + '佛手柑' => ' fó shǒu gān', + '燕歌行' => ' yān gē xíng', + '孔夫子' => ' kǒng fū zǐ', + '海陆空' => ' hǎi lù kòng', + '误差值' => ' wù chā zhí', + '外边儿' => ' wài bian r', + '赔不是' => ' péi bú shì', + '腮帮子' => ' sāi bāng zǐ', + '供佛花' => ' gòng fó huā', + '电驴子' => ' diàn lǘ zǐ', + '莲都区' => ' lián dū qū', + '法隆寺' => ' fǎ lōng sì', + '铜离子' => ' tóng lí zǐ', + '薄荷糖' => ' bò he táng', + '西洲曲' => ' xī zhōu qǔ', + '薄荷醇' => ' bò he chún', + '铜子儿' => ' tóng zǐ er', + '搞不懂' => ' gǎo bu dǒng', + '血淋淋' => ' xiě lín lín', + '来得早' => ' lái de zǎo', + '出尖儿' => ' chū jiān r', + '怎么着' => ' zěn me zhāo', + '谈得来' => ' tán de lái', + '金樱子' => ' jīn yīng zǐ', + '葵花子' => ' kuí huā zǐ', + '猪尾巴' => ' zhū wěi ba', + '波隆那' => ' bō lōng nà', + '葛法翁' => ' gě fǎ wēng', + '豆角儿' => ' dòu jué ér', + '出漏子' => ' chū lòu zǐ', + '调压器' => ' tiáo yā qì', + '葡萄干' => ' pú táo gān', + '线坯子' => ' xiàn pī zǐ', + '出岔子' => ' chū chà zǐ', + '未处理' => ' wèi chǔ lǐ', + '曾祖父' => ' zēng zǔ fù', + '电喇叭' => ' diàn lǎ ba', + '书记处' => ' shū ji chù', + '走门子' => ' zǒu mén zǐ', + '当家子' => ' dāng jiā zǐ', + '佛光寺' => ' fó guāng sì', + '笑呵呵' => ' xiào hē hē', + '老莱子' => ' lǎo lái zǐ', + '小姑子' => ' xiǎo gū zǐ', + '走样儿' => ' zǒu yàng r', + '走形儿' => ' zǒu xíng r', + '小肚子' => ' xiǎo dǔ zi', + '质子数' => ' zhì zǐ shù', + '没空儿' => ' méi kòng r', + '书馆儿' => ' shū guǎn r', + '曾祖母' => ' zēng zǔ mǔ', + '天老爷' => ' tiān lǎo ye', + '着劲儿' => ' zhuó jìn r', + '后边儿' => ' hòu bian r', + '烘干机' => ' hōng gān jī', + '颠儿面' => ' diān r miàn', + '曾纪泽' => ' zēng jì zé', + '瞎琢磨' => ' xiā zuó mo', + '说头儿' => ' shuō tou er', + '西塞山' => ' xī sài shān', + '蒙古族' => ' měng gǔ zú', + '蒙古语' => ' měng gǔ yǔ', + '落不是' => ' luò bú shì', + '小女子' => ' xiǎo nǚ zǐ', + '柞丝绸' => ' zuò sī chóu', + '切削液' => ' qiē xiāo yè', + '附着物' => ' fù zhuó wù', + '真子集' => ' zhēn zǐ jí', + '合不着' => ' hé bù zháo', + '脊柱炎' => ' jǐ zhù yán', + '小摊儿' => ' xiǎo tān r', + '拓扑学' => ' tuò pū xué', + '辣椒仔' => ' là jiāo zǎi', + '狄更斯' => ' dí gēng sī', + '折跟头' => ' zhē gēn tou', + '摆阔气' => ' bǎi kuò qi', + '没什么' => ' méi shén me', + '黏糊糊' => ' nián hū hū', + '看不出' => ' kàn bu chū', + '死难者' => ' sǐ nàn zhě', + '雅诺什' => ' yǎ nuò shí', + '理发匠' => ' lǐ fà jiàng', + '刮舌子' => ' guā shé zǐ', + '热应力' => ' rè yìng lì', + '行业语' => ' háng yè yǔ', + '兴奋剂' => ' xīng fèn jì', + '斗地主' => ' dòu dì zhǔ', + '别着急' => ' bié zháo jí', + '余干县' => ' yú gān xiàn', + '雪佛兰' => ' xuě fó lán', + '捣练子' => ' dǎo liàn zǐ', + '任务书' => ' rèn wu shū', + '卜算子' => ' bǔ suàn zǐ', + '会计师' => ' kuài jì shī', + '龈擦音' => ' yín cā yīn', + '接泊车' => ' jiē bó chē', + '无脊椎' => ' wú jǐ zhuī', + '合同法' => ' hé tong fǎ', + '馊点子' => ' sōu diǎn zǐ', + '打跟头' => ' dǎ gēn tou', + '脱壳机' => ' tuō qiào jī', + '龈辅音' => ' yín fǔ yīn', + '不对劲' => ' bú duì jìn', + '过家家' => ' guō jiā jiā', + '玛曲县' => ' mǎ qǔ xiàn', + '不要紧' => ' bú yào jǐn', + '每个人' => ' měi ge rén', + '知不道' => ' zhì bù dào', + '齿龈炎' => ' chǐ yín yán', + '宿舍楼' => ' sù shè lóu', + '狗崽子' => ' gǒu zǎi zǐ', + '动干戈' => ' dòng gān gē', + '头脸儿' => ' tóu liǎn r', + '齿龈音' => ' chǐ yín yīn', + '认识论' => ' rèn shi lùn', + '没得说' => ' méi de shuō', + '不在行' => ' bù zài háng', + '看热闹' => ' kàn rè nao', + '肉丸子' => ' ròu wán zǐ', + '下边儿' => ' xià bian r', + '脱不了' => ' tuō bù liǎo', + '猜不透' => ' cāi bu tòu', + '印古什' => ' yìn gǔ shí', + '阿物儿' => ' ā wù r', + '瓜子金' => ' guā zǐ jīn', + '猜谜儿' => ' cāi mèi ér', + '离子键' => ' lí zǐ jiàn', + '猜得透' => ' cāi de tòu', + '风流子' => ' fēng liú zǐ', + '大麦町' => ' dà mài tǐng', + '好得很' => ' hǎo de hěn', + '电子门' => ' diàn zǐ mén', + '厦门市' => ' xià mén shì', + '鲁子敬' => ' lǔ zǐ jìng', + '鸡血石' => ' jī xiě shí', + '马尾辫' => ' mǎ yǐ biàn', + '捞什子' => ' lāo shí zi', + '出乱子' => ' chū luàn zǐ', + '粘合机' => ' nián hé jī', + '知制诰' => ' zhī zhì gào', + '京油子' => ' jīng yóu zǐ', + '南蛮子' => ' nán mán zǐ', + '鼻梁子' => ' bí liáng zǐ', + '司天台' => ' sī tiān tāi', + '不一定' => ' bù yí dìng', + '受难日' => ' shòu nàn rì', + '燕尾蝶' => ' yān wěi dié', + '好得多' => ' hǎo de duō', + '雪佛莱' => ' xuě fó lái', + '假招子' => ' jiǎ zhāo zǐ', + '牙龈炎' => ' yá yín yán', + '牛仔布' => ' níu zǎi bù', + '盐坨子' => ' yán tuó zǐ', + '子午线' => ' zǐ wǔ xiàn', + '拉大便' => ' là dà biàn', + '冬瓜子' => ' dōng guā zǐ', + '挂不住' => ' guà bú zhù', + '风荷载' => ' fēng hè zài', + '君子兰' => ' jūn zǐ lán', + '史丹佛' => ' shǐ dān fó', + '子公司' => ' zǐ gōng sī', + '找碴儿' => ' zhǎo chá r', + '差错率' => ' chā cuò lǜ', + '娃娃脸' => ' wá wa liǎn', + '云浮市' => ' yún fú shì', + '乳杆菌' => ' rǔ gǎn jūn', + '对工儿' => ' duì gōng r', + '支努干' => ' zhī nǔ gān', + '主合同' => ' zhǔ hé tong', + '直发板' => ' zhí fà bǎn', + '面条儿' => ' miàn tiáo r', + '瞧得起' => ' qiáo de qǐ', + '卷地皮' => ' juàn dì pí', + '电子论' => ' diàn zǐ lùn', + '谐振子' => ' xié zhèn zǐ', + '顺嘴儿' => ' shùn zuǐ r', + '曲江区' => ' qǔ jiāng qū', + '纪录片' => ' jì lù piān', + '调制波' => ' tiáo zhì bō', + '理发厅' => ' lǐ fà tīng', + '理发院' => ' lǐ fà yuàn', + '分子病' => ' fēn zǐ bìng', + '韩非子' => ' hán fēi zǐ', + '理发员' => ' lǐ fà yuán', + '不是事' => ' bú shì shì', + '热干面' => ' rè gān miàn', + '体己钱' => ' tī ji qián', + '狗腿子' => ' gǒu tuǐ zǐ', + '曲射炮' => ' qǔ shè pào', + '容不得' => ' róng bu dé', + '欧巴桑' => ' ōu ba sāng', + '理发店' => ' lǐ fà diàn', + '安公子' => ' ān gōng zǐ', + '黑芝麻' => ' hēi zhī ma', + '男子单' => ' nán zǐ dān', + '姜子牙' => ' jiāng zǐ yá', + '的士高' => ' dí shì gāo', + '再发见' => ' zài fā xiàn', + '藏族人' => ' zàng zú rén', + '做功夫' => ' zuò gōng fu', + '不失为' => ' bù shī wéi', + '做工夫' => ' zuò gōng fu', + '子弟兵' => ' zǐ dì bīng', + '对不住' => ' duì bú zhù', + '反面儿' => ' fǎn miàn r', + '说不出' => ' shuō bu chū', + '犟劲儿' => ' jiàng jìn r', + '核子能' => ' hé zǐ néng', + '娃娃生' => ' wá wa shēng', + '钻门子' => ' zuàn mén zǐ', + '掷骰子' => ' zhì tóu zǐ', + '着色剂' => ' zhuó sè jì', + '不见得' => ' bú jiàn de', + '除不尽' => ' chú bù jìn', + '滥套子' => ' làn tào zǐ', + '犯不着' => ' fàn bù zháo', + '小家子' => ' xiǎo jiā zǐ', + '目的性' => ' mù dì xìng', + '薄油层' => ' bó yóu céng', + '子宫癌' => ' zǐ gōng ái', + '那些个' => ' nèi xiē gè', + '名角儿' => ' míng jué r', + '薄烤饼' => ' bó kǎo bǐng', + '注射液' => ' zhù shè yè', + '目的港' => ' mù dì gǎng', + '调味剂' => ' tiáo wèi jì', + '济南市' => ' jǐ nán shì', + '菜子油' => ' cài zǐ yóu', + '那么着' => ' nà me zhāo', + '原子核' => ' yuán zǐ hé', + '饭馆儿' => ' fàn guǎn r', + '败家子' => ' bài jiā zǐ', + '原子笔' => ' yuán zǐ bǐ', + '回弹力' => ' huí tán lì', + '吴堡县' => ' wú bǔ xiàn', + '参与者' => ' cān yù zhě', + '窃以为' => ' qiè yǐ wéi', + '不尽根' => ' bù jìn gēn', + '男子汉' => ' nán zǐ hàn', + '切削力' => ' qiē xuē lì', + '犯得着' => ' fàn de zháo', + '弓弦儿' => ' gōng xián r', + '无患子' => ' wú huàn zǐ', + '进行曲' => ' jìn xíng qǔ', + '酸奶子' => ' suān nǎi zǐ', + '不对头' => ' bú duì tóu', + '拓跋魏' => ' tuò bá wèi', + '高分子' => ' gāo fèn zǐ', + '高勾丽' => ' gāo gōu lí', + '逼供信' => ' bī gòng xìn', + '白干儿' => ' bái gān ér', + '一次性' => ' yí cì xìng', + '拖尾巴' => ' tuō wěi ba', + '酸处理' => ' suān chǔ lǐ', + '不干涉' => ' bù gān shè', + '虎爪派' => ' hǔ zhuǎ pài', + '预应力' => ' yù yìng lì', + '活塞杆' => ' huó sāi gǎn', + '后发座' => ' hòu fà zuò', + '白切鸡' => ' bái qiē jī', + '会计学' => ' kuài jì xué', + '满剌加' => ' mǎn là jiā', + '内应力' => ' nèi yìng lì', + '六环路' => ' lìu huán lù', + '会计室' => ' kuài jì shì', + '锭子油' => ' dìng zǐ yóu', + '一溜烟' => ' yī liú yān', + '不应期' => ' bù yìng qī', + '散腿裤' => ' sǎn tuǐ kù', + '小弟弟' => ' xiǎo dì di', + '白芝麻' => ' bái zhī ma', + '分子键' => ' fēn zǐ jiàn', + '这会子' => ' zhè huì zǐ', + '择日子' => ' zhái rì zi', + '粘度计' => ' nián dù jì', + '会厌炎' => ' huì yàn yán', + '无名帖' => ' wú míng tiě', + '开卷机' => ' kāi juàn jī', + '子宫壁' => ' zǐ gōng bì', + '古惑仔' => ' gǔ huò zǎi', + '脏兮兮' => ' zāng xī xī', + '看得过' => ' kàn de guò', + '曲艺团' => ' qǔ yì tuán', + '合得着' => ' hé de zháo', + '高句丽' => ' gāo gōu lí', + '拐弯儿' => ' guǎi wān r', + '上一个' => ' shàng yī ge', + '电子业' => ' diàn zǐ yè', + '炸丸子' => ' zhá wán zǐ', + '电子式' => ' diàn zǐ shì', + '粘糊糊' => ' nián hū hū', + '兴凯湖' => ' xīng kǎi hú', + '年头儿' => ' nián tóu r', + '这么着' => ' zhè me zhāo', + '费工夫' => ' fèi gōng fu', + '脾切除' => ' pí qiē chú', + '离子源' => ' lí zǐ yuán', + '干涉仪' => ' gān shè yí', + '离子能' => ' lí zǐ néng', + '虎而冠' => ' hǔ ér guàn', + '吃得消' => ' chī de xiāo', + '土著人' => ' tǔ zhù rén', + '弹射器' => ' tán shè qì', + '不值当' => ' bù zhí dàng', + '茶馆儿' => ' chá guǎn r', + '芝麻包' => ' zhī ma bāo', + '迎头儿' => ' yíng tóu r', + '老油子' => ' lǎo yóu zǐ', + '押运员' => ' yā yùn yuán', + '小妮子' => ' xiǎo nī zǐ', + '莱佛士' => ' lái fó shì', + '兴宾区' => ' xīng bīn qū', + '没准儿' => ' méi zhǔn r', + '洋娃娃' => ' yáng wá wa', + '复兴区' => ' fù xīng qū', + '劳什子' => ' láo shí zǐ', + '电子流' => ' diàn zǐ liú', + '大月氏' => ' dà ròu zhī', + '亲家母' => ' qìng jiā mǔ', + '连轧机' => ' lián zhá jī', + '坎肩儿' => ' kǎn jiān r', + '新乐府' => ' xīn yuè fǔ', + '转矩臂' => ' zhuàn jǔ bì', + '立合同' => ' lì hé tong', + '平埔族' => ' píng pǔ zú', + '花骨朵' => ' huā gū duǒ', + '理发馆' => ' lǐ fà guǎn', + '坊子区' => ' fāng zǐ qū', + '倒座儿' => ' dǎo zuò ér', + '卸载器' => ' xiè zǎi qì', + '汤婆子' => ' tāng pó zǐ', + '年画儿' => ' nián huà r', + '德兴市' => ' dé xīng shì', + '干扰素' => ' gān rǎo sù', + '芸苔子' => ' yún tái zǐ', + '花边儿' => ' huā biān r', + '冷负荷' => ' lěng fù hè', + '回旋曲' => ' huí xuán qǔ', + '芫花素' => ' yuán huā sù', + '转速比' => ' zhuàn sù bǐ', + '德都县' => ' dé dū xiàn', + '办不到' => ' bàn bú dào', + '弹花机' => ' tán huā jī', + '圆舞曲' => ' yuán wǔ qǔ', + '大氧吧' => ' dà yǎng bā', + '跑神儿' => ' pǎo shén r', + '动荷载' => ' dòng hè zài', + '花旗参' => ' huā qí shēn', + '反知识' => ' fǎn zhī shi', + '皮桶子' => ' pí tǒng zǐ', + '弹跳力' => ' tán tiào lì', + '自适应' => ' zì shì yìng', + '古典乐' => ' gǔ diǎn yuè', + '修指甲' => ' xīu zhǐ jia', + '痱子粉' => ' fèi zǐ fěn', + '类似点' => ' lèi sì diǎn', + '不对称' => ' bù duì chèn', + '趁早儿' => ' chèn zǎo r', + '血豆腐' => ' xiě dòu fǔ', + '脑门子' => ' nǎo mén zǐ', + '那时候' => ' nà shí hou', + '乌良哈' => ' wū liáng hǎ', + '那倒是' => ' nà dào shi', + '尽可能' => ' jìn kě néng', + '脚丫子' => ' jiǎo yā zǐ', + '擂台赛' => ' lèi tái sài', + '逻辑学' => ' luó ji xué', + '佛法僧' => ' fó fǎ sēng', + '风信子' => ' fēng xìn zǐ', + '佛出世' => ' fó chū shì', + '那曲县' => ' nǎ qū xiàn', + '豆腐羹' => ' dòu fu gēng', + '架不住' => ' jià bú zhù', + '蹦高儿' => ' bèng gāo r', + '勒索者' => ' lè suǒ zhě', + '万户侯' => ' wàn hù hòu', + '肋膜炎' => ' lèi mó yán', + '万柏林' => ' wàn bó lín', + '探亲假' => ' tàn qīn jià', + '小胡子' => ' xiǎo hú zǐ', + '芝麻饼' => ' zhī ma bǐng', + '超负荷' => ' chāo fù hè', + '参与制' => ' cān yù zhì', + '小曲儿' => ' xiǎo qǔ ér', + '坐月子' => ' zuò yuè zǐ', + '那程子' => ' nà chéng zǐ', + '台面呢' => ' tái miàn ní', + '月子病' => ' yuè zǐ bìng', + '得样儿' => ' de yàng ér', + '花点子' => ' huā diǎn zǐ', + '李隆基' => ' lǐ lōng jī', + '卸担子' => ' xiè dàn zi', + '放印子' => ' fàng yìn zǐ', + '较劲儿' => ' jiào jìn r', + '洋画儿' => ' yáng huà r', + '泪人儿' => ' lèi rén ér', + '莫泊桑' => ' mò bó sāng', + '小姨子' => ' xiǎo yí zǐ', + '小苏打' => ' xiǎo sū dá', + '抽嘴巴' => ' chōu zuǐ ba', + '反弹力' => ' fǎn tán lì', + '身板儿' => ' shēn bǎn r', + '话篓子' => ' huà lǒu zǐ', + '东阿县' => ' dōng ē xiàn', + '鬼故事' => ' guǐ gù shi', + '童子痨' => ' tóng zǐ láo', + '太子参' => ' tài zǐ shēn', + '子囊菌' => ' zǐ náng jūn', + '牟平区' => ' mù píng qū', + '八斗才' => ' bā dǒu cái', + '烧茄子' => ' shāo qié zi', + '电子伏' => ' diàn zǐ fú', + '拇指甲' => ' mǔ zhǐ jia', + '草甸子' => ' cǎo diàn zǐ', + '拗不过' => ' niù bù guò', + '热得快' => ' rè de kuài', + '鹤嘴镐' => ' hè zuǐ hào', + '洒狗血' => ' sǎ gǒu xiě', + '脑萎缩' => ' nǎo wěi suō', + '阳离子' => ' yáng lí zǐ', + '不调和' => ' bù tiáo hé', + '苦差事' => ' kǔ chāi shì', + '不均匀' => ' bù jūn yún', + '黄陂区' => ' huáng pí qū', + '扩散板' => ' kuò sǎn bǎn', + '燃灯佛' => ' rán dēng fó', + '汉乐府' => ' hàn yuè fǔ', + '不着家' => ' bù zháo jiā', + '吃空额' => ' chī kòng é', + '不作为' => ' bù zuò wéi', + '调节器' => ' tiáo jié qì', + '氢离子' => ' qīng lí zǐ', + '着色力' => ' zhuó sè lì', + '寒山子' => ' hán shān zǐ', + '独山子' => ' dú shān zǐ', + '调酒器' => ' tiáo jǐu qì', + '卿大夫' => ' qīng dài fū', + '马尾松' => ' mǎ yǐ sōng', + '麻麻亮' => ' mā mɑ liàng', + '蔡甸区' => ' cài diàn qū', + '黄埔区' => ' huáng pǔ qū', + '测量机' => ' cè liáng jī', + '汉堡包' => ' hàn pù bāo', + '果子酒' => ' guǒ zǐ jiǔ', + '革吉县' => ' gé jí xiàn', + '乐都县' => ' lè dū xiàn', + '吃不住' => ' chī bú zhù', + '寒暑假' => ' hán shǔ jià', + '靠得住' => ' kào de zhù', + '咔哒声' => ' kǎ da shēng', + '调色板' => ' tiáo sè bǎn', + '卸肩儿' => ' xiè jiān r', + '拉个手' => ' lā ge shǒu', + '死胡同' => ' sǐ hú tòng', + '登徒子' => ' dēng tú zǐ', + '死劲儿' => ' sǐ jìng er', + '靠不住' => ' kào bú zhù', + '小娃娃' => ' xiǎo wá wa', + '吃得住' => ' chī de zhù', + '吃得开' => ' chī de kāi', + '人贩子' => ' rén fàn zǐ', + '苣荬菜' => ' qǔ mǎi cài', + '逆反应' => ' nì fǎn yìng', + '子弹带' => ' zǐ dàn dài', + '小伙儿' => ' xiǎo huǒ r', + '隐君子' => ' yǐn jūn zǐ', + '曲靖市' => ' qǔ jìng shì', + '切肉刀' => ' qiē ròu dāo', + '摸不着' => ' mō bù zháo', + '疏勒国' => ' shū lè guó', + '踏莎行' => ' tà suō xíng', + '吧托女' => ' bā tuō nǔ:', + '独生子' => ' dú shēng zǐ', + '娃娃兵' => ' wá wa bīng', + '兴义市' => ' xīng yì shì', + '南瓜子' => ' nán guā zǐ', + '东边儿' => ' dōng biān r', + '补给舰' => ' bǔ jǐ jiàn', + '香薄荷' => ' xiāng bò he', + '阿华田' => ' a huà tián', + '香胰子' => ' xiāng yí zǐ', + '玄菟郡' => ' xuán tù jùn', + '雕刻刀' => ' diāo kè dāo', + '大堡礁' => ' dà pù jiāo', + '洗发水' => ' xǐ fà shuǐ', + '挨呲儿' => ' ái cī r', + '这些个' => ' zhèi xiē gè', + '调侃儿' => ' tiáo kǎn ér', + '小夜曲' => ' xiǎo yè qǔ', + '对对子' => ' duì duì zǐ', + '认不是' => ' rèn bú shì', + '抱佛脚' => ' bào fó jiǎo', + '脊索瘤' => ' jǐ suǒ liú', + '太过分' => ' tài guò fèn', + '子模型' => ' zǐ mó xíng', + '质子泵' => ' zhì zǐ bèng', + '右边儿' => ' yòu bian r', + '切割刀' => ' qiē gē dāo', + '掰腕子' => ' bāi wàn zǐ', + '玩儿坏' => ' wán r huài', + '尉犁县' => ' yù lí xiàn', + '瘾君子' => ' yǐn jūn zǐ', + '牛仔裤' => ' niú zǎi kù', + '挨时间' => ' ái shí jiān', + '察合台' => ' chá gě tái', + '木头人' => ' mù tou rén', + '筒子楼' => ' tǒng zǐ lóu', + '起五更' => ' qǐ wǔ gēng', + '死不了' => ' sǐ bù liǎo', + '抄靶子' => ' chāo bǎ zǐ', + '迷惑龙' => ' mí huo lóng', + '国子监' => ' guó zǐ jiàn', + '牛脊肉' => ' níu jǐ ròu', + '狗仔队' => ' gǒu zǎi duì', + '到了儿' => ' dào liǎo er', + '托勒玫' => ' tuō lè méi', + '喇叭形' => ' lǎ ba xíng', + '跟屁股' => ' gēn pì gu', + '喉塞音' => ' hóu sè yīn', + '叭啦狗' => ' bā lā gǒu', + '黑糊糊' => ' hēi hū hū', + '一部分' => ' yī bù fen', + '乌干达' => ' wū gān dá', + '乌拉圭' => ' wù lɑ guī', + '鱼肚白' => ' yú dǔ bái', + '暗门子' => ' àn mén zǐ', + '发小儿' => ' fà xiǎo r', + '牙缝儿' => ' yá fèng r', + '润发露' => ' rùn fà lù', + '润发液' => ' rùn fà yè', + '安魂曲' => ' ān hún qǔ', + '牡丹区' => ' mǔ dan qū', + '龈腭音' => ' yín è yīn', + '牡丹卡' => ' mǔ dan kǎ', + '武都市' => ' wǔ dū shì', + '暗楼子' => ' àn lóu zǐ', + '阿克苏' => ' a kè sū', + '阿克拉' => ' a kè lā', + '不值得' => ' bù zhí de', + '可不是' => ' kě bú shì', + '一甲子' => ' yī jiǎ zǐ', + '撒拉铁' => ' sǎ lā tiě', + '可数集' => ' kě shǔ jí', + '热处理' => ' rè chǔ lǐ', + '合得来' => ' hé de lái', + '鼻咽癌' => ' bí yān ái', + '撒切尔' => ' sā qiē ěr', + '殷都区' => ' yīn dū qū', + '欧柏林' => ' oū bó lín', + '挂钩儿' => ' guà gōu r', + '不由得' => ' bù yóu de', + '百子图' => ' bǎi zǐ tú', + '男子气' => ' nán zǐ qì', + '男孩儿' => ' nán hái r', + '番禺区' => ' pān yú qū', + '氨吖啶' => ' ān ā dìng', + '颚龈音' => ' è yín yīn', + '不舒服' => ' bù shū fu', + '折子戏' => ' zhé zǐ xì', + '麦盖提' => ' mài gě tí', + '龈颚音' => ' yín è yīn', + '丽佳娜' => ' lí jiā nà', + '史密斯' => ' shǐ mì sī', + '盐都区' => ' yán dū qū', + '烟头儿' => ' yān tóu r', + '无支祁' => ' wú zhī qí', + '鹍鸡曲' => ' kūn jī qǔ', + '熟道儿' => ' shú dào r', + '三部曲' => ' sān bù qǔ', + '吉卜赛' => ' jí bǔ sài', + '炸子鸡' => ' zhá zǐ jī', + '齐柏林' => ' qí bó lín', + '魏都区' => ' wèi dū qū', + '诸葛弩' => ' zhū gě nǔ', + '子弟书' => ' zǐ dì shū', + '一家子' => ' yī jiā zǐ', + '卢塞恩' => ' lú sài ēn', + '没六儿' => ' méi lìu r', + '和得来' => ' hé de lái', + '笔头儿' => ' bǐ tou er', + '零杂儿' => ' líng zá r', + '和散那' => ' hé sǎn nà', + '和稀泥' => ' huò xī ní', + '白麻子' => ' bái má zǐ', + '摆设儿' => ' bǎi she r', + '如来佛' => ' rú lái fó', + '没门儿' => ' méi mén r', + '自以为' => ' zì yǐ wéi', + '洗发皂' => ' xǐ fà zào', + '一个人' => ' yí ge rén', + '瘾头儿' => ' yǐn tóu r', + '阴离子' => ' yīn lí zǐ', + '涂尔干' => ' tú ěr gān', + '阿堵物' => ' ē dǔ wù', + '背搭子' => ' bèi dā zǐ', + '孺子牛' => ' rú zǐ niú', + '杜笃玛' => ' dù dǔ mǎ', + '西耶那' => ' xī yē nà', + '核子力' => ' hé zǐ lì', + '炮儿局' => ' pào r jú', + '没劲儿' => ' méi jìn r', + '没奈何' => ' mò nài hé', + '一水儿' => ' yī shuǐ r', + '笔杆儿' => ' bǐ gǎn ér', + '切割器' => ' qiē gē qì', + '下一个' => ' xià yī ge', + '切割机' => ' qiē gē jī', + '歌仔戏' => ' gē zǎi xì', + '挨板子' => ' ái bǎn zi', + '海蛤蝓' => ' hǎi gé yú', + '卡脖子' => ' qiǎ bó zi', + '挨边儿' => ' āi biān r', + '没溜儿' => ' méi lìu r', + '挨头子' => ' ái tóu zi', + '辟支佛' => ' pì zhī fó', + '杂件儿' => ' zá jiàn r', + '洗发粉' => ' xǐ fà fěn', + '散座儿' => ' sǎn zuò r', + '直发器' => ' zhí fà qì', + '白班儿' => ' bái bān r', + '捋胳膊' => ' luō gē bo', + '波尔干' => ' bō ěr gān', + '一个劲' => ' yí gè jìn', + '捋虎须' => ' luō hǔ xū', + '印把子' => ' yìn bà zi', + '鼻咽部' => ' bí yān bù', + '尽义务' => ' jìn yì wù', + '阿伊努' => ' a yī nǔ', + '反粒子' => ' fǎn lì zǐ', + '舍利塔' => ' shè lì tǎ', + '苦活儿' => ' kǔ huó r', + '虚套子' => ' xū tào zǐ', + '补给品' => ' bǔ jǐ pǐn', + '微粒子' => ' wēi lì zǐ', + '脱衣服' => ' tuō yī fu', + '畜牧学' => ' xù mù xué', + '臭子儿' => ' chòu zǐ r', + '果子露' => ' guǒ zǐ lù', + '果子狸' => ' guǒ zǐ lí', + '果仁儿' => ' guǒ rén r', + '副书记' => ' fù shū ji', + '枕席儿' => ' zhěn xí r', + '续随子' => ' xù suí zǐ', + '剥皮器' => ' bāo pí qì', + '买不起' => ' mǎi bu qǐ', + '柏克郡' => ' bó kè jùn', + '牙花子' => ' yá huā zǐ', + '阿合奇' => ' a hé qí', + '使劲儿' => ' shǐ jìn r', + '脑瓜儿' => ' nǎo guā r', + '脑脊液' => ' nǎo jǐ yè', + '来得及' => ' lái de jí', + '枸杞子' => ' gǒu qǐ zǐ', + '来火儿' => ' lái huǒ r', + '临月儿' => ' lín yuè r', + '缩砂密' => ' sù shā mì', + '猫眼儿' => ' māo yǎn r', + '费劲儿' => ' fèi jìn r', + '四君子' => ' sì jūn zǐ', + '记号笔' => ' jì hao bǐ', + '软泥儿' => ' ruǎn ní r', + '五倍子' => ' wǔ bèi zǐ', + '记不住' => ' jì bu zhù', + '西边儿' => ' xī biān r', + '西门子' => ' xī mén zǐ', + '内比都' => ' nèi bǐ dū', + '触技曲' => ' chù jì qǔ', + '土粉子' => ' tǔ fěn zǐ', + '里边儿' => ' lǐ bian r', + '拓扑图' => ' tuò pū tú', + '土狗子' => ' tǔ gǒu zǐ', + '脱模剂' => ' tuō mú jì', + '阿玛尼' => ' a mǎ ní', + '脱模器' => ' tuō mú qì', + '许廑父' => ' xǔ qín fù', + '脱模机' => ' tuō mú jī', + '认人儿' => ' rèn rén r', + '阿瓦提' => ' a wǎ tí', + '兔崽子' => ' tù zǎi zǐ', + '起小兒' => ' qǐ xiǎo r', + '曼德勒' => ' màn dé lè', + '费米子' => ' fèi mǐ zǐ', + '蜗杆副' => ' wō gǎn fù', + '费德勒' => ' fèi dé lè', + '花都区' => ' huā dū qū', + '别客气' => ' bié kè qi', + '铺路石' => ' pū lù shí', + '熬不住' => ' áo bú zhù', + '熬头儿' => ' áo tou er', + '理发师' => ' lǐ fà shī', + '武侯祠' => ' wǔ hòu cí', + '不可数' => ' bù kě shǔ', + '器乐曲' => ' qì yuè qǔ', + '一揽子' => ' yī lǎn zǐ', + '马赛曲' => ' mǎ sài qǔ', + '马约卡' => ' mǎ yāo kǎ', + '马塞卢' => ' mǎ sài lú', + '不含糊' => ' bù hán hu', + '马勃菌' => ' mǎ bó jùn', + '拨子弹' => ' bō zǐ tán', + '班辈儿' => ' bān bèi r', + '不安分' => ' bù ān fèn', + '扑脸儿' => ' pū liǎn r', + '子母扣' => ' zǐ mǔ kòu', + '半拉子' => ' bàn lǎ zǐ', + '破谜儿' => ' pò mèi ér', + '浑球儿' => ' hún qíu r', + '呀诺达' => ' yā nuò dá', + '呆会儿' => ' dāi huì r', + '字帖儿' => ' zì tiě er', + '剥皮机' => ' bāo pí jī', + '抱娃娃' => ' bào wá wa', + '扬子鳄' => ' yáng zǐ è', + '取灯儿' => ' qǔ dēng r', + '血糊糊' => ' xiě hū hū', + '都卜勒' => ' dōu bǔ lè', + '开普勒' => ' kāi pǔ lè', + '朴子市' => ' pò zǐ shì', + '迦叶佛' => ' jiā yè fó', + '曲麻莱' => ' qǔ má lái', + '丝挂子' => ' sī guà zǐ', + '阿卡提' => ' a kǎ dī', + '部落格' => ' bù luò gé', + '俄勒冈' => ' e lè gāng', + '舍利子' => ' shè lì zǐ', + '配对儿' => ' pèi duì r', + '暾欲谷' => ' tūn yù gǔ', + '都伯林' => ' dū bó lín', + '独院儿' => ' dú yuàn r', + '芋头色' => ' yù tou sè', + '那维克' => ' nǎ wéi kè', + '芥子气' => ' jiè zǐ qì', + '那曲市' => ' nà qǔ shì', + '刮胡子' => ' guā hú zǐ', + '泡沫剂' => ' pāo mò jì', + '毗耶娑' => ' pí yē suō', + '不在乎' => ' bù zài hu', + '余甘子' => ' yú gān zǐ', + '玩儿完' => ' wán r wán', + '吐谷浑' => ' tǔ yù hún', + '子大夫' => ' zǐ dài fū', + '大姨子' => ' dà yí zǐ', + '苦不唧' => ' kǔ bu jī', + '洗发膏' => ' xǐ fà gāo', + '阿赖耶' => ' ā lài yē', + '阿斯兰' => ' a sī lán', + '阿勒泰' => ' a lè tài', + '迂夫子' => ' yū fū zǐ', + '阿图什' => ' a tú shí', + '泥娃娃' => ' ní wá wa', + '哈喇子' => ' hā lǎ zǐ', + '可劲儿' => ' kě jìn r', + '斗趣儿' => ' dòu qù r', + '扎鲁特' => ' zā lǔ tè', + '四部曲' => ' sì bù qǔ', + '阿奎纳' => ' a kuí nà', + '阿森斯' => ' a sēn sī', + '鸡子儿' => ' jī zǐ er', + '遗腹子' => ' yí fù zǐ', + '刺儿话' => ' cì r huà', + '拉撒路' => ' lā sǎ lù', + '阿森纳' => ' a sēn nà', + '阿閦佛' => ' a chù fó', + '阿贝尔' => ' a bèi ěr', + '打趸儿' => ' dǎ dǔn r', + '鸭子儿' => ' yā zǐ er', + '哥德堡' => ' gē dé pù', + '那话儿' => ' nà huà r', + '撒播机' => ' sǎ bō jī', + '杂牌儿' => ' zá pái r', + '扒头儿' => ' bā tou r', + '阿阇梨' => ' ā shé lí', + '大衣呢' => ' dà yī ní', + '顾不得' => ' gù bu de', + '呕吐物' => ' ǒu tù wù', + '爱玉子' => ' ài yù zǐ', + '头箍儿' => ' tóu gū r', + '氯离子' => ' lǜ lí zǐ', + '马褡子' => ' mǎ dā zǐ', + '努嘴儿' => ' nǔ zuǐ r', + '骨碌碌' => ' gū lù lù', + '大姑子' => ' dà gū zǐ', + '大气儿' => ' dà qì r', + '钠离子' => ' nà lí zǐ', + '哪一个' => ' nǎ yī ge', + '吉娃娃' => ' jí wá wa', + '大苏打' => ' dà sū dá', + '刺儿李' => ' cì r lǐ', + '一拨儿' => ' yī bō r', + '努劲儿' => ' nǔ jìn r', + '惹不起' => ' rě bu qǐ', + '拿得起' => ' ná de qǐ', + '恶名儿' => ' è míng r', + '哈巴河' => ' hā bā hé', + '古希腊' => ' gǔ xī là', + '马服子' => ' mǎ fú zǐ', + '阿布贾' => ' a bù jiǎ', + '阿兰若' => ' ā lán rě', + '阿阇黎' => ' ā shé lí', + '玩艺儿' => ' wán yì r', + '在那儿' => ' zài na r', + '菩提子' => ' pú tí zǐ', + '破衣服' => ' pò yī fu', + '书皮儿' => ' shū pí r', + '地肤子' => ' dì fū zǐ', + '护发乳' => ' hù fà rǔ', + '土坎儿' => ' tǔ kǎn r', + '离子膜' => ' lí zǐ mó', + '德勒兹' => ' dé lè zī', + '提篮儿' => ' tí lán r', + '提头儿' => ' tí tóu r', + '鼻洼子' => ' bí wā zǐ', + '负离子' => ' fù lí zǐ', + '模糊集' => ' mó hu jí', + '笆篱子' => ' bā lí zǐ', + '锂离子' => ' lǐ lí zǐ', + '赋格曲' => ' fù gé qǔ', + '贝壳儿' => ' bèi ké r', + '土木堡' => ' tǔ mù pù', + '替角儿' => ' tì jué r', + '替班儿' => ' tì bān r', + '弥勒佛' => ' mí lè fó', + '塞席尔' => ' sè xí ěr', + '呼啦啦' => ' hū lā lā', + '护发素' => ' hù fà sù', + '拉勾儿' => ' lā gòu r', + '热负荷' => ' rè fù hè', + '阿马逊' => ' a mǎ xùn', + '鱼钩儿' => ' yú gōu r', + '打屁股' => ' dǎ pì gu', + '阿维拉' => ' a wéi lā', + '阿尔泰' => ' a ěr tài', + '合辙儿' => ' hé zhé r', + '搭茬儿' => ' dā chá r', + '阿瑞斯' => ' a ruì sī', + '拉肚子' => ' lā dǔ zi', + '哥们儿' => ' gē men r', + '撒丫子' => ' sā yā zǐ', + '雅尔塔' => ' yá ěr tǎ', + '打顿儿' => ' dǎ dùn r', + '阿美族' => ' a měi zú', + '阿凡达' => ' a fán dá', + '拿撒勒' => ' ná sǎ lè', + '阿肯色' => ' a kěn sè', + '凹朴皮' => ' āo pò pí', + '卡哇伊' => ' kǎ wā yī', + '阿盖达' => ' a gài dá', + '闭子集' => ' bì zǐ jí', + '阿初佛' => ' a chū fó', + '阿依莎' => ' a yī shā', + '阿伊莎' => ' a yī shā', + '阿克伦' => ' a kè lún', + '阿克陶' => ' a kè táo', + '阿凡提' => ' a fán tí', + '嘎拉哈' => ' gā lā hà', + '玻色子' => ' bō sè zǐ', + '河西堡' => ' hé xī pù', + '夜盆儿' => ' yè pén r', + '一对儿' => ' yī duì r', + '虚粒子' => ' xū lì zǐ', + '媳妇子' => ' xí fù zǐ', + '细伢子' => ' xì yá zǐ', + '薄一波' => ' bó yī bō', + '大剌剌' => ' dà là là', + '子不语' => ' zǐ bù yǔ', + '几乎不' => ' jī hū bù', + '莫伯日' => ' mò bó rì', + '洗发露' => ' xǐ fà lù', + '兹沃勒' => ' zī wò lè', + '子目录' => ' zǐ mù lù', + '子午仪' => ' zǐ wǔ yí', + '比不上' => ' bǐ bù shǎng', + '庵摩勒' => ' ān mó lè', + '库尔勒' => ' kù ěr lè', + '蜡坨儿' => ' là tuó r', + '栖息地' => ' qī xī dì', + '阿法尔' => ' a fǎ ěr', + '竹箍儿' => ' zhú gū r', + '奥米伽' => ' ào mǐ gā', + '奥塞梯' => ' aò sè tī', + '歌曲集' => ' gē qǔ jí', + '渔歌子' => ' yú gē zǐ', + '西子湖' => ' xī zǐ hú', + '渔钩儿' => ' yú gōu r', + '五子棋' => ' wǔ zǐ qí', + '六合区' => ' lù hé qū', + '孤立子' => ' gū lì zǐ', + '被窝儿' => ' bèi wō r', + '克耶族' => ' kè yē zú', + '阿姆河' => ' a mǔ hé', + '克蕾儿' => ' kè lěi r', + '洗发乳' => ' xǐ fà rǔ', + '洗发剂' => ' xǐ fà jì', + '大肚子' => ' dà dǔ zi', + '子集合' => ' zǐ jí hé', + '讨底儿' => ' tǎo dǐ r', + '法耶德' => ' fǎ yē dé', + '法勒斯' => ' fǎ lè sī', + '借字儿' => ' jiè zì r', + '欧米伽' => ' ōu mǐ gā', + '个头儿' => ' gè tóu r', + '帽箍儿' => ' mào gū r', + '没谱儿' => ' méi pǔ r', + '葫芦科' => ' hú lu kē', + '衣钩儿' => ' yī gōu r', + '子夜歌' => ' zǐ yè gē', + '菟丝子' => ' tù sī zi', + '武把子' => ' wǔ bà zi', + '卧佛寺' => ' wò fó sì', + '阿爸父' => ' a bà fù', + '痰盂儿' => ' tán yú r', + '箍节儿' => ' gū jie r', + '瓦勒他' => ' wǎ lè tā', + '不答理' => ' bù dā lǐ', + '密麻麻' => ' mì mā mɑ', + '阿巴斯' => ' a bā sī', + '邷么儿' => ' wǎ mó r', + '自个儿' => ' zì gě ér', + '巴勒莫' => ' bā lè mò', + '奇蹄目' => ' jī tí mù', + '纹丝儿' => ' wén sī r', + '纸马儿' => ' zhǐ mǎ r', + '窝脖儿' => ' wō bó r', + '不拉几' => ' bù lā jī', + '自各儿' => ' zì gě r', + '畜牧业' => ' xù mù yè', + '柏柏尔' => ' bò bò ěr', + '娃娃鱼' => ' wá wa yú', + '咖喱鸡' => ' gā lí jī', + '伊妹儿' => ' yī mèi r', + '塔塔儿' => ' tǎ tǎ r', + '伍子胥' => ' wǔ zǐ xū', + '一路哭' => ' yí lù kū', + '伺服器' => ' sì fú qì', + '格子呢' => ' gé zi ní', + '八哥儿' => ' bā gē r', + '马尾区' => ' mǎ wěi qū', + '瓦都兹' => ' wǎ dū zī', + '柏拉图' => ' bó lā tú', + '热剌剌' => ' rè là là', + '乐呵呵' => ' lè hē hē', + '阿拉尔' => ' a lā ěr', + '姑爷爷' => ' gū yé ye', + '阿提拉' => ' a tí lā', + '鼓子词' => ' gǔ zǐ cí', + '阿拉瓦' => ' a lā wǎ', + '孤哀子' => ' gū āi zǐ', + '尼勒克' => ' ní lè kè', + '尼泊尔' => ' ní bó ěr', + '屁眼儿' => ' pì yǎn r', + '目的地' => ' mù dì dì', + '耶弗他' => ' yē fú tā', + '耶利米' => ' yē lì mǐ', + '阿拉斯' => ' a lā sī', + '希腊语' => ' xī là yǔ', + '胡琴儿' => ' hú qín r', + '阿拉摩' => ' a lā mó', + '阿拉伯' => ' a lā bó', + '一肚子' => ' yī dǔ zi', + '耳挖子' => ' ěr wā zǐ', + '老客儿' => ' lǎo kè r', + '武都区' => ' wǔ dū qū', + '佛骨塔' => ' fó gǔ tǎ', + '比特币' => ' bǐ tè bì', + '布娃娃' => ' bù wá wa', + '阿希姆' => ' a xī mǔ', + '希特勒' => ' xī tè lè', + '薄熙来' => ' bó xī lái', + '稀释液' => ' xī shì yè', + '贼骨头' => ' zéi gú tou', + '花子儿' => ' huā zǐ er', + '伽罗瓦' => ' jiā luó wà', + '伏都教' => ' fú dū jiào', + '附着力' => ' fù zhuó lì', + '节假日' => ' jié jià rì', + '经得起' => ' jīng de qǐ', + '绕弯子' => ' rào wān zǐ', + '夹尾巴' => ' jiā wěi ba', + '捋袖子' => ' luō xìu zi', + '爱好者' => ' ài hào zhě', + '夹当儿' => ' jiā dāng r', + '孙女儿' => ' sūn nǔ: r', + '不舍得' => ' bù shě de', + '翟理斯' => ' zhái lǐ sī', + '哇沙比' => ' wā shā bǐ', + '狐媚子' => ' hú mèi zǐ', + '薄荷脑' => ' bò he nǎo', + '子细胞' => ' zǐ xì bāo', + '哇沙米' => ' wā shā mǐ', + '安南子' => ' ān nán zǐ', + '孙媳夫' => ' sūn xí fu', + '宜都市' => ' yí dū shì', + '安德肋' => ' an dé lèi', + '孙武子' => ' sūn wǔ zǐ', + '挎兜儿' => ' kuà dōu r', + '催干剂' => ' cuī gān jì', + '美发师' => ' měi fà shī', + '不自禁' => ' bù zì jīn', + '使君子' => ' shǐ jūn zǐ', + '罗刹女' => ' luó chà nǚ', + '勒索罪' => ' lè suǒ zuì', + '约维克' => ' yāo wéi kè', + '干扰机' => ' gān rǎo jī', + '人尖儿' => ' rén jiān r', + '红胡子' => ' hóng hú zǐ', + '人为土' => ' rén wéi tǔ', + '于都县' => ' yú dū xiàn', + '干妹子' => ' gàn mèi zǐ', + '奇函数' => ' jī hán shù', + '奇偶性' => ' jī ǒu xìng', + '昆都仑' => ' kūn dū lún', + '美智子' => ' měi zhì zǐ', + '金龟子' => ' jīn guī zǐ', + '夫子庙' => ' fū zǐ miào', + '父子兵' => ' fù zǐ bīng', + '左边儿' => ' zuǒ bian r', + '钓钩儿' => ' diào gōu r', + '罗伯逊' => ' luō bó xùn', + '罗圈儿' => ' luó quān r', + '罗夫诺' => ' luō fū nuò', + '罗姆酒' => ' luō mǔ jǐu', + '片子地' => ' piān zi dì', + '惹乱子' => ' rě luàn zǐ', + '子母弹' => ' zǐ mǔ dàn', + '咖喱粉' => ' gā lí fěn', + '吹胡子' => ' chuī hú zǐ', + '钙离子' => ' gài lí zǐ', + '马扎子' => ' mǎ zhá zǐ', + '马尾藻' => ' mǎ yǐ zǎo', + '马奶子' => ' mǎ nǎi zǐ', + '麻麻黑' => ' mā mɑ hēi', + '处女地' => ' chǔ nǚ dì', + '麻雷子' => ' má léi zǐ', + '喷嘴儿' => ' pēn zuǐ r', + '码垛机' => ' mǎ duò jī', + '哗啦啦' => ' huā lā lā', + '夹肢窝' => ' gā zhī wō', + '嘴巴子' => ' zuǐ ba zi', + '夹塞儿' => ' jiā sāi r', + '满负荷' => ' mǎn fù hè', + '咖喱饭' => ' gā lí fàn', + '路倒儿' => ' lù dǎo er', + '惹麻烦' => ' rě má fan', + '浮头儿' => ' fú tou er', + '惠斯勒' => ' huì sī lè', + '大都市' => ' dà dū shì', + '塞勒姆' => ' sāi lè mǔ', + '夜宵儿' => ' yè xiāo r', + '耳掴子' => ' ěr guó zǐ', + '待会儿' => ' dāi huì r', + '多粒子' => ' duō lì zǐ', + '买得起' => ' mǎi de qǐ', + '高拨子' => ' gāo bō zǐ', + '话把儿' => ' huà bà er', + '禁得起' => ' jīn de qǐ', + '拜把子' => ' bài bà zi', + '柏林寺' => ' bó lín sì', + '牌子曲' => ' pái zi qǔ', + '华达呢' => ' huá dá ní', + '大部分' => ' dà bù fèn', + '拆烂污' => ' cā làn wū', + '回单儿' => ' huí dān r', + '刘阿斗' => ' liú ā dǒu', + '打得好' => ' dǎ de hǎo', + '差速器' => ' chā sù qì', + '大师傅' => ' dà shī fū', + '金缕曲' => ' jīn lǚ qǔ', + '奇蹄类' => ' jī tí lèi', + '太仆寺' => ' tài pú sì', + '富家子' => ' fù jiā zǐ', + '金娃娃' => ' jīn wá wa', + '刀把儿' => ' dāo bà er', + '布什尔' => ' bù shí ěr', + '希思罗' => ' xī sī luō', + '希腊文' => ' xī là wén', + '分子力' => ' fèn zǐ lì', + '打不倒' => ' dǎ bù dǎo', + '打摆子' => ' dǎ bǎi zǐ', + '大都会' => ' dà dū huì', + '懂门儿' => ' dǒng mén r', + '紫坪铺' => ' zǐ píng pū', + '拉呱儿' => ' lā guā er', + '佛得角' => ' fó dé jiǎo', + '漂浮物' => ' piāo fú wù', + '音乐剧' => ' yīn yuè jù', + '耶稣教' => ' yē sū jiào', + '摇篮曲' => ' yáo lán qǔ', + '大袋鼠' => ' dà dài shǔ', + '打哈欠' => ' dǎ hā qian', + '耶烈万' => ' yē liè wàn', + '大家伙' => ' dà jiā huo', + '大姐姐' => ' dà jiě jie', + '大咧咧' => ' dà liē liē', + '是不是' => ' shì bú shì', + '耶诞节' => ' yē dàn jié', + '吃得来' => ' chī de lái', + '佛教徒' => ' fó jiào tú', + '佛教语' => ' fó jiào yǔ', + '佛朗哥' => ' fó lǎng gē', + '数一数' => ' shǔ yī shù', + '耳坠子' => ' ěr zhuì zǐ', + '药引子' => ' yào yǐn zǐ', + '佛朗机' => ' fó lǎng jī', + '老骨头' => ' lǎo gú tou', + '老毛子' => ' lǎo máo zǐ', + '女人家' => ' nǚ rén jia', + '老处女' => ' lǎo chǔ nǚ', + '吃得下' => ' chī de xià', + '干燥机' => ' gān zào jī', + '老头儿' => ' lǎo tou er', + '煤烟子' => ' méi yān zǐ', + '箭靶子' => ' jiàn bǎ zǐ', + '乐谱架' => ' yuè pǔ jià', + '鱼秧子' => ' yú yāng zǐ', + '闷头儿' => ' mèn tou er', + '捎马子' => ' shāo mǎ zǐ', + '保得住' => ' bǎo de zhù', + '数不尽' => ' shù bu jìn', + '榛仁儿' => ' zhēn rén r', + '玉米粥' => ' yù mǐ zhōu', + '煤砟子' => ' méi zhǎ zǐ', + '房牙子' => ' fáng yá zǐ', + '伛偻病' => ' yú lǚ bìng', + '干燥剂' => ' gān zào jì', + '闷子车' => ' mèn zǐ chē', + '榜葛剌' => ' bǎng gé là', + '好奇心' => ' hào qí xīn', + '禁不住' => ' jīn bú zhù', + '乐府诗' => ' yuè fǔ shī', + '阿城区' => ' a chéng qū', + '协奏曲' => ' xié zòu qǔ', + '枪把儿' => ' qiāng bà r', + '票友儿' => ' piào yǒu r', + '尿盆儿' => ' niào pén r', + '溜边儿' => ' līu biān r', + '京都府' => ' jīng dū fǔ', + '呼啦圈' => ' hū lā quān', + '介子推' => ' jiè zǐ tuī', + '累加器' => ' lěi jiā qì', + '肖伯纳' => ' xiāo bó nà', + '消食儿' => ' xiāo shí r', + '镚子儿' => ' bèng zǐ er', + '厚薄规' => ' hòu bó guī', + '柏青哥' => ' bó qīng gē', + '四子王' => ' sì zǐ wáng', + '大轴子' => ' dà zhòu zǐ', + '背包客' => ' bēi bāo kè', + '背包袱' => ' bēi bāo fú', + '背影儿' => ' bèi yǐng r', + '接头儿' => ' jiē tou er', + '慢累积' => ' màn lěi jī', + '大少爷' => ' dà shào yé', + '干酪素' => ' gān lào sù', + '日月晕' => ' rì yuè yùn', + '是非题' => ' shì fēi tí', + '左撇子' => ' zuǒ piě zǐ', + '使绊子' => ' shǐ bàn zǐ', + '愣劲儿' => ' lèng jìn r', + '世家子' => ' shì jiā zǐ', + '什叶派' => ' shí yè pài', + '阿鲁巴' => ' a lǔ bā', + '乱麻麻' => ' luàn mā mɑ', + '结对子' => ' jié duì zǐ', + '大宛马' => ' dà yuān mǎ', + '禁得住' => ' jīn de zhù', + '大包干' => ' dà bāo gān', + '戴假发' => ' dài jiǎ fà', + '溜溜儿' => ' liū liù ér', + '女主角' => ' nǚ zhǔ jué', + '一般般' => ' yì bān bān', + '六君子' => ' liù jūn zǐ', + '大单于' => ' dà chán yú', + '六个月' => ' liù ge yuè', + '洋码子' => ' yáng mǎ zǐ', + '负电子' => ' fù diàn zǐ', + '翻篇儿' => ' fān piān r', + '酒令儿' => ' jǐu lìng r', + '柏辽兹' => ' bó liáo zī', + '胡椒子' => ' hú jiāo zǐ', + '负电荷' => ' fù diàn hè', + '担不是' => ' dān bú shì', + '派不是' => ' pài bú shì', + '酒馆儿' => ' jǐu guǎn r', + '脊柱裂' => ' jǐ zhù liè', + '释迦佛' => ' shì jiā fó', + '烟贩子' => ' yān fàn zǐ', + '烟斗丝' => ' yān dǒu sī', + '后处理' => ' hòu chǔ lǐ', + '作曲家' => ' zuò qǔ jiā', + '水磨机' => ' shuǐ mò jī', + '太子丹' => ' tài zǐ dān', + '佛蒙特' => ' fó méng tè', + '多目的' => ' duō mù dì', + '喇叭口' => ' lǎ ba kǒu', + '载伯德' => ' zǎi bó dé', + '碰磁儿' => ' pèng cí r', + '红箍儿' => ' hóng gū r', + '阿斯旺' => ' a sī wàng', + '阿尔山' => ' a ěr shān', + '阿洛菲' => ' a luò fēi', + '在那里' => ' zài nà li', + '干巴巴' => ' gān bā bā', + '阿荣旗' => ' a róng qí', + '阿曼湾' => ' a màn wān', + '碑座儿' => ' bēi zuò r', + '傻呵呵' => ' shǎ hē hē', + '晕乎乎' => ' yùn hū hū', + '阿拉善' => ' a lā shàn', + '耶和华' => ' yē hé huá', + '阿拉丁' => ' a lā dīng', + '磨得开' => ' mó de kāi', + '禁不起' => ' jīn bù qǐ', + '阿多诺' => ' a duō nuò', + '福安市' => ' fú ān shì', + '阿坝县' => ' a bà xiàn', + '石鼓区' => ' dàn gǔ qū', + '阿瑟县' => ' a sè xiàn', + '占地儿' => ' zhàn dì r', + '看得起' => ' kàn de qǐ', + '阿里郎' => ' a lǐ láng', + '加的斯' => ' jiā dì sī', + '耳刮子' => ' ěr guā zǐ', + '阿兰文' => ' a lán wén', + '羞答答' => ' xiū dā dā', + '染发剂' => ' rǎn fà jì', + '加勒比' => ' jiā lè bǐ', + '佛舍利' => ' fó shè lì', + '佛兰德' => ' fó lán dé', + '佛诞日' => ' fó dàn rì', + '胡燕妮' => ' hú yān nī', + '野孩子' => ' yě hái zǐ', + '加劲儿' => ' jiā jìn r', + '耶酥会' => ' yē sū huì', + '铁钩儿' => ' tiě gōu r', + '老妈子' => ' lǎo mā zǐ', + '一竿子' => ' yī gān zǐ', + '耙耳朵' => ' pā ěr duo', + '早班儿' => ' zǎo bān r', + '旱鸭子' => ' hàn yā zǐ', + '老伯伯' => ' lǎo bó bo', + '老佛爷' => ' lǎo fó yé', + '石磨机' => ' shí mò jī', + '耶稣会' => ' yē sū huì', + '阿卢巴' => ' a lú bā', + '一刹那' => ' yī chà nà', + '柳子戏' => ' liǔ zǐ xì', + '老帽儿' => ' lǎo mào r', + '老爷爷' => ' lǎo yé ye', + '眵目糊' => ' chī mu hū', + '阿瑟镇' => ' a sè zhèn', + '扣眼儿' => ' kòu yǎn r', + '五斗米' => ' wǔ dǒu mǐ', + '开花儿' => ' kāi huā r', + '五味子' => ' wǔ wèi zǐ', + '杰佛兹' => ' jié fó zī', + '做伴儿' => ' zuò bàn r', + '木齿耙' => ' mù chǐ pá', + '车份儿' => ' chē fèn r', + '躲不起' => ' duǒ bu qǐ', + '阿皮亚' => ' a pí yà', + '苏打粉' => ' sū dá fěn', + '木子美' => ' mù zǐ měi', + '处女膜' => ' chǔ nǚ mó', + '处理器' => ' chǔ lǐ qì', + '笔杆子' => ' bǐ gǎn zi', + '跑味儿' => ' pǎo wèi r', + '五大夫' => ' wǔ dài fū', + '傻帽儿' => ' shǎ mào r', + '薄荷油' => ' bò he yóu', + '赶得及' => ' gǎn de jí', + '葛缕子' => ' gě lǔ: zi', + '弹力丝' => ' tán lì sī', + '弹力袜' => ' tán lì wà', + '借单儿' => ' jiè dān r', + '戏报子' => ' xì bào zǐ', + '蔡李佛' => ' cài lǐ fó', + '开都河' => ' kāi dū hé', + '第四台' => ' dì sì tái', + '阿苏山' => ' a sū shān', + '亚曼牙' => ' yà màn yá', + '干儿子' => ' gān ér zi', + '阿莱曼' => ' a lái màn', + '阿育王' => ' ā yù wáng', + '阿罗约' => ' a luó yuē', + '阿的平' => ' ā dì píng', + '色差仪' => ' sè chā yí', + '石子儿' => ' shí zǐ er', + '石河子' => ' shí hé zǐ', + '阿坝州' => ' a bà zhōu', + '阿加维' => ' a jiā wéi', + '粒子流' => ' lì zǐ liú', + '梅西耶' => ' méi xī yē', + '一下子' => ' yī xià zǐ', + '六安市' => ' lù ān shì', + '粒子束' => ' lì zǐ shù', + '门坎儿' => ' mén kǎn r', + '秦都区' => ' qín dū qū', + '二流子' => ' èr liú zǐ', + '鱼丸子' => ' yú wán zǐ', + '阿伯丁' => ' a bó dīng', + '预处理' => ' yù chǔ lǐ', + '窝里反' => ' wō li fǎn', + '窝里斗' => ' wō li dòu', + '半分儿' => ' bàn fēn r', + '二里头' => ' er lǐ tou', + '针箍儿' => ' zhēn gū r', + '罗锅儿' => ' luó guō r', + '捆扎机' => ' kǔn zā jī', + '抓子儿' => ' zhuā zǐ r', + '大伯子' => ' dà bǎi zǐ', + '老婆子' => ' lǎo pó zǐ', + '发疟子' => ' fā yào zǐ', + '老夫子' => ' lǎo fū zǐ', + '度假区' => ' dù jià qū', + '得尔塔' => ' děi ěr tǎ', + '卷叶蛾' => ' juàn yè é', + '单子叶' => ' dān zǐ yè', + '宝葫芦' => ' bǎo hú lu', + '宝贝儿' => ' bǎo bèi r', + '积累率' => ' jī lěi lǜ', + '鸡内金' => ' jī nà jīn', + '老爷子' => ' lǎo yé zǐ', + '磨粉机' => ' mò fěn jī', + '找刺儿' => ' zhǎo cì r', + '对劲儿' => ' duì jìn r', + '对味儿' => ' duì wèi r', + '对得起' => ' duì de qǐ', + '对心儿' => ' duì xīn r', + '批处理' => ' pī chǔ lǐ', + '抹得开' => ' mò de kāi', + '娃娃菜' => ' wá wa cài', + '哈巴狗' => ' hǎ bā gǒu', + '阿萨德' => ' a sà dé', + '滴溜儿' => ' dī liù ér', + '尧都区' => ' yáo dū qū', + '活局子' => ' huó jú zǐ', + '堵塞费' => ' dǔ sè fèi', + '多普勒' => ' duō pǔ lè', + '夜猫子' => ' yè māo zǐ', + '多佛尔' => ' duō fó ěr', + '墨水儿' => ' mò shuǐ r', + '阿衣奴' => ' a yī nǔ', + '独奏曲' => ' dú zòu qǔ', + '弹涂鱼' => ' tán tú yú', + '压不碎' => ' yā bu suì', + '都御使' => ' dū yù shǐ', + '克分子' => ' kè fèn zǐ', + '后钩儿' => ' hòu gōu r', + '地窨子' => ' dì yìn zǐ', + '培勒兹' => ' péi lè zī', + '粪箕子' => ' fèn jī zǐ', + '大袋子' => ' dà dài zi', + '大舅子' => ' dà jiù zǐ', + '酒嗉子' => ' jiǔ sù zǐ', + '旧衣服' => ' jiù yī fu', + '离子束' => ' lí zǐ shù', + '离子流' => ' lí zǐ liú', + '大文蛤' => ' dà wén gé', + '在一起' => ' zài yì qǐ', + '类似于' => ' lèi sì yú', + '类似物' => ' lèi sì wù', + '哥特式' => ' gē tè shì', + '闹肚子' => ' nào dǔ zi', + '以此为' => ' yǐ cǐ wéi', + '一路货' => ' yí lù huò', + '打短儿' => ' dǎ duǎn r', + '打旋儿' => ' dǎ xuán r', + '喀喇沁' => ' kā lā qìn', + '打把式' => ' dǎ bǎ shi', + '打嘴巴' => ' dǎ zuǐ ba', + '打不过' => ' dǎ bu guò', + '折刀儿' => ' zhé dāo r', + '腿肚子' => ' tuǐ dǔ zi', + '一路人' => ' yí lù rén', + '勒维夫' => ' lè wéi fu', + '新都区' => ' xīn dū qū', + '一溜儿' => ' yī liù ér', + '启发式' => ' qǐ fà shì', + '继子女' => ' jì zǐ nǔ:', + '十八子' => ' shí bā zǐ', + '勒威耶' => ' lè wēi yē', + '任一个' => ' rèn yī ge', + '纹缕儿' => ' wén lǔ: r', + '纳匝肋' => ' nà zā lèi', + '绝门儿' => ' jué mén r', + '斯坦佛' => ' sī tǎn fó', + '斯宾塞' => ' sī bīn sè', + '以斯帖' => ' yǐ sī tiě', + '阿萨姆' => ' a sà mǔ', + '啦啦队' => ' lā lā duì', + '托勒密' => ' tuō lè mì', + '岔曲儿' => ' chà qǔ er', + '戳个儿' => ' chuō gè r', + '南歌子' => ' nán gē zǐ', + '哪门子' => ' nǎ mén zǐ', + '拿不住' => ' ná bú zhù', + '娃娃车' => ' wá wa chē', + '娃娃亲' => ' wá wa qīn', + '哈什蚂' => ' ha shi mà', + '宝坻区' => ' bǎo dǐ qū', + '折过儿' => ' zhē guò r', + '过去佛' => ' guò qù fó', + '目的论' => ' mù dì lùn', + '墨斗鱼' => ' mò dǒu yú', + '敕勒歌' => ' chì lè gē', + '古乐府' => ' gǔ yuè fǔ', + '奶嘴儿' => ' nǎi zuǐ r', + '奴儿干' => ' nú ér gān', + '门弟子' => ' mén dì zǐ', + '搁得住' => ' gé de zhù', + '镁离子' => ' měi lí zǐ', + '搁不住' => ' gé bú zhù', + '煤核儿' => ' méi hú ér', + '高压脊' => ' gāo yā jǐ', + '压根儿' => ' yà gēn ér', + '骨朵儿' => ' gū duǒ er', + '扳本儿' => ' bān běn r', + '抹不开' => ' mò bù kāi', + '一面倒' => ' yī miàn dǎo', + '尽全力' => ' jìn quán lì', + '独唱曲' => ' dú chàng qǔ', + '相适应' => ' xiāng shì yìng', + '兴隆县' => ' xīng lóng xiàn', + '孔子庙' => ' kǒng zǐ miào', + '泼脏水' => ' pō zāng shuǐ', + '谈朋友' => ' tán péng you', + '弹跳板' => ' tán tiào bǎn', + '调节者' => ' tiáo jié zhě', + '有年头' => ' yǒu nián tou', + '响应值' => ' xiǎng yìng zhí', + '电子表' => ' diàn zǐ biǎo', + '壁效应' => ' bì xiào yìng', + '相位表' => ' xiàng wèi biǎo', + '典当业' => ' diǎn dàng yè', + '外行话' => ' wài háng huà', + '连接框' => ' lián jiē kuàng', + '诸葛亮' => ' zhū gě liàng', + '偏差值' => ' piān chā zhí', + '土党参' => ' tǔ dǎng shēn', + '两边倒' => ' liǎng biān dǎo', + '曾金燕' => ' zēng jīn yàn', + '招待会' => ' zhāo dāi huì', + '望都县' => ' wàng dū xiàn', + '绷弓子' => ' bēng gōng zi', + '谁知道' => ' shéi zhī dào', + '振兴区' => ' zhèn xīng qū', + '陪产假' => ' péi chǎn jià', + '片儿汤' => ' piān er tāng', + '相电流' => ' xiàng diàn liú', + '长治市' => ' cháng zhì shì', + '感应电' => ' gǎn yìng diàn', + '教学片' => ' jiào xué piān', + '甩脸子' => ' shuǎi liǎn zǐ', + '适应症' => ' shì yìng zhèng', + '兴中会' => ' xīng zhōng huì', + '兴城市' => ' xīng chéng shì', + '宝兴县' => ' bǎo xīng xiàn', + '长相思' => ' zhǎng xiàng sī', + '当世冠' => ' dāng shì guàn', + '长乐宫' => ' cháng lè gōng', + '施甸县' => ' shī diàn xiàn', + '迎新会' => ' yíng xīn kuài', + '粮食厅' => ' liáng shi tīng', + '流行性' => ' liú xíng xìng', + '银行券' => ' yín háng juàn', + '不正当' => ' bù zhèng dàng', + '钻牛角' => ' zuàn niú jiǎo', + '孪生子' => ' luán shēng zǐ', + '管弦乐' => ' guǎn xián yuè', + '角斗场' => ' jué dòu chǎng', + '用得上' => ' yòng de shàng', + '长清区' => ' cháng qīng qū', + '调酒师' => ' tiáo jǐu shī', + '漂白粉' => ' piǎo bái fěn', + '陈省身' => ' chén xǐng shēn', + '电荷泵' => ' diàn hè bèng', + '调味品' => ' tiáo wèi pǐn', + '有弹性' => ' yǒu tán xìng', + '电熨斗' => ' diàn yùn dǒu', + '冰凝器' => ' bīng níng qì', + '八重奏' => ' bā chóng zòu', + '出风头' => ' chū fēng tou', + '眼镜框' => ' yǎn jìng kuàng', + '贡嘎县' => ' gòng gá xiàn', + '牛仔衫' => ' niú zǎi shān', + '涂浆台' => ' tú jiàng tái', + '命名法' => ' mìng míng fǎ', + '谢长廷' => ' xiè cháng tíng', + '命名日' => ' mìng míng rì', + '病秧子' => ' bìng yāng zǐ', + '免不了' => ' miǎn bù liǎo', + '呱呱叫' => ' guā guā jiào', + '伸舌头' => ' shēn shé tou', + '调解书' => ' tiáo jiě shū', + '音乐厅' => ' yīn yuè tīng', + '长袍儿' => ' cháng páo er', + '抓功夫' => ' zhuā gōng fu', + '应聘者' => ' yìng pìn zhě', + '单房差' => ' dān fáng chā', + '点电荷' => ' diǎn diàn hè', + '弹簧钢' => ' tán huáng gāng', + '猪仔馆' => ' zhū zǎi guǎn', + '丰都县' => ' fēng dū xiàn', + '曾孝谷' => ' zēng xiào gǔ', + '指甲剪' => ' zhǐ jia jiǎn', + '背饥荒' => ' bēi jī huāng', + '两着儿' => ' liǎng zhāo r', + '空调器' => ' kōng tiáo qì', + '调药刀' => ' tiáo yào dāo', + '彭丽媛' => ' péng lì yuán', + '浪荡子' => ' làng dàng zǐ', + '两下子' => ' liǎng xià zǐ', + '曾繁仁' => ' zēng fán rén', + '挑衅者' => ' tiǎo xìn zhě', + '王尽美' => ' wáng jìn měi', + '曾国藩' => ' zēng guó fān', + '兴山县' => ' xīng shān xiàn', + '空调机' => ' kōng tiáo jī', + '长公主' => ' cháng gōng zhǔ', + '电子战' => ' diàn zǐ zhàn', + '拍卖行' => ' pāi mài háng', + '长兴岛' => ' cháng xīng dǎo', + '双曲面' => ' shuāng qǔ miàn', + '冠军赛' => ' guàn jūn sài', + '挑花眼' => ' tiǎo huā yǎn', + '苯中毒' => ' běn zhòng dú', + '调味汁' => ' tiáo wèi zhī', + '交响曲' => ' jiāo xiǎng qǔ', + '长沙湾' => ' cháng shā wān', + '蒜茸钳' => ' suàn róng qián', + '量角器' => ' liáng jiǎo qì', + '香泡树' => ' xiāng pāo shù', + '金山屯' => ' jīn shān zhūn', + '钉书针' => ' dìng shū zhēn', + '犯得上' => ' fàn děi shàng', + '罗甸县' => ' luó diàn xiàn', + '海螵蛸' => ' hǎi piāo xiāo', + '校正子' => ' jiào zhèng zǐ', + '美容觉' => ' měi róng jiào', + '首相府' => ' shǒu xiàng fǔ', + '犍为县' => ' qián wèi xiàn', + '翟志刚' => ' zhái zhì gāng', + '弹簧锁' => ' tán huáng suǒ', + '粘着性' => ' zhān zhuó xìng', + '命中率' => ' mìng zhòng lǜ', + '长春市' => ' cháng chūn shì', + '村上隆' => ' cūn shàng lōng', + '想倒美' => ' xiǎng dǎo měi', + '缝衣匠' => ' féng yī jiàng', + '旋风脚' => ' xuàn fēng jiǎo', + '延长线' => ' yán cháng xiàn', + '檀香扇' => ' tán xiāng shàn', + '弄明白' => ' nòng míng bai', + '亲家公' => ' qìng jiā gōng', + '爱漂亮' => ' ài piào liang', + '应用性' => ' yìng yòng xìng', + '昌都县' => ' chāng dū xiàn', + '石头城' => ' shí tou chéng', + '重庆市' => ' chóng qìng shì', + '长短句' => ' cháng duǎn jù', + '赶得上' => ' gǎn děi shàng', + '飞将军' => ' fēi jiàng jūn', + '弹簧门' => ' tán huáng mén', + '正安县' => ' zhēng an xiàn', + '长春子' => ' cháng chūn zǐ', + '紧绷绷' => ' jǐn bēng bēng', + '请假条' => ' qǐng jià tiáo', + '钻井队' => ' zuàn jǐng duì', + '钱串子' => ' qián chuàn zǐ', + '长筒靴' => ' cháng tǒng xuē', + '世界上' => ' shì jiè shang', + '唐三藏' => ' táng sān zàng', + '藏经洞' => ' zàng jīng dòng', + '绍兴市' => ' shào xīng shì', + '绍兴酒' => ' shào xīng jiǔ', + '风切变' => ' fēng qiē biàn', + '止疼片' => ' zhǐ téng piān', + '校正器' => ' jiào zhèng qì', + '结婚证' => ' jiē hūn zhèng', + '始兴县' => ' shǐ xīng xiàn', + '应用文' => ' yìng yòng wén', + '一场空' => ' yī cháng kōng', + '交响乐' => ' jiāo xiǎng yuè', + '强迫症' => ' qiǎng pò zhèng', + '订书钉' => ' dìng shū dīng', + '应力场' => ' yìng lì chǎng', + '长宁区' => ' cháng níng qū', + '印相纸' => ' yìn xiàng zhǐ', + '供应舰' => ' gōng yìng jiàn', + '延长县' => ' yán cháng xiàn', + '长子县' => ' cháng zǐ xiàn', + '方框图' => ' fāng kuàng tú', + '小旋风' => ' xiǎo xuàn fēng', + '长寿区' => ' cháng shòu qū', + '光波长' => ' guāng bō cháng', + '长沙市' => ' cháng shā shì', + '新兴县' => ' xīn xīng xiàn', + '兜率天' => ' dōu shuài tiān', + '光感应' => ' guāng gǎn yìng', + '传记性' => ' zhuàn jì xìng', + '动画片' => ' dòng huà piān', + '斜长石' => ' xié cháng shí', + '长武县' => ' cháng wǔ xiàn', + '感应圈' => ' gǎn yìng quān', + '长期性' => ' cháng qī xìng', + '干燥箱' => ' gān zào xiāng', + '兜率宫' => ' dōu shuài gōng', + '应景诗' => ' yìng jǐng shī', + '干燥症' => ' gān zào zhèng', + '番茄酱' => ' fān qié jiàng', + '撞运气' => ' zhuàng yùn qi', + '脏躁症' => ' zāng zào zhèng', + '工伤假' => ' gōng shāng jià', + '应召站' => ' yìng zhào zhàn', + '海兴县' => ' hǎi xīng xiàn', + '长岛县' => ' cháng dǎo xiàn', + '杓球场' => ' sháo qíu chǎng', + '长城卡' => ' cháng chéng kǎ', + '供应站' => ' gòng yīng zhàn', + '藏红花' => ' zàng hóng huā', + '瞭望哨' => ' liào wàng shào', + '请病假' => ' qǐng bìng jià', + '侍应生' => ' shì yìng shēng', + '钦天监' => ' qīn tiān jiàn', + '男傧相' => ' nán bīn xiàng', + '说得上' => ' shuō de shàng', + '弹簧刀' => ' tán huáng dāo', + '瓶塞钻' => ' píng sāi zuàn', + '粘滞性' => ' nián zhì xìng', + '长洲区' => ' cháng zhōu qū', + '鹿角霜' => ' lù jiǎo shuāng', + '长方体' => ' cháng fāng tǐ', + '精校本' => ' jīng jiào běn', + '灯笼椒' => ' dēng long jiāo', + '商都县' => ' shāng dū xiàn', + '增温层' => ' zēng wēn céng', + '全武行' => ' quán wǔ háng', + '重甸甸' => ' zhòng diàn diàn', + '取景框' => ' qǔ jǐng kuàng', + '跟不上' => ' gēn bu shàng', + '长城牌' => ' cháng chéng pái', + '曲松县' => ' qǔ sōng xiàn', + '搓麻将' => ' cuō má jiàng', + '千佛山' => ' qiān fó shān', + '曲柄钻' => ' qū bǐng zuàn', + '曲水县' => ' qǔ shuǐ xiàn', + '良家子' => ' liáng jiā zǐ', + '转腰子' => ' zhuàn yāo zi', + '弹棉花' => ' tán mián huā', + '还魂纸' => ' huán hún zhǐ', + '微中子' => ' wēi zhōng zǐ', + '吊膀子' => ' diào bàng zi', + '车行道' => ' chē háng dào', + '复兴党' => ' fù xīng dǎng', + '天仙子' => ' tiān xiān zǐ', + '切向力' => ' qiē xiàng lì', + '分子量' => ' fèn zǐ liàng', + '粘性土' => ' nián xìng tǔ', + '调节板' => ' tiáo jié bǎn', + '调节池' => ' tiáo jié chí', + '娘子军' => ' niáng zǐ jūn', + '累进税' => ' lěi jìn shuì', + '更年期' => ' gēng nián qī', + '两个月' => ' liǎng ge yuè', + '司天监' => ' sī tiān jiàn', + '转差率' => ' zhuǎn chā lǜ', + '长庚星' => ' cháng gēng xīng', + '卷心菜' => ' juàn xīn cài', + '山桐子' => ' shān tóng zǐ', + '协方差' => ' xié fāng chā', + '银行家' => ' yín háng jiā', + '调解人' => ' tiáo jiě rén', + '金晃晃' => ' jīn huàng huǎng', + '粘合胶' => ' nián hé jiāo', + '速调管' => ' sù tiáo guǎn', + '门边框' => ' mén biān kuàng', + '曲阳县' => ' qǔ yáng xiàn', + '这年头' => ' zhè nián tou', + '搬楦头' => ' bān xuàn tou', + '不着调' => ' bù zháo diào', + '遇难船' => ' yù nàn chuán', + '圆石头' => ' yuán shí tou', + '弹钢琴' => ' tán gāng qín', + '转铃儿' => ' zhuàn líng r', + '转轴儿' => ' zhuàn zhóu r', + '运货员' => ' yùn huò yuán', + '忘不了' => ' wàng bù liǎo', + '粮食局' => ' liáng shi jú', + '两三个' => ' liǎng sān ge', + '还原剂' => ' huán yuán jì', + '冷脸子' => ' lěng liǎn zǐ', + '转字锁' => ' zhuàn zì suǒ', + '扎囊县' => ' zā náng xiàn', + '想不到' => ' xiǎng bú dào', + '金曲奖' => ' jīn qǔ jiǎng', + '受得了' => ' shòu de liǎo', + '长安街' => ' cháng ān jiē', + '切削刃' => ' qiē xiāo rèn', + '星子县' => ' xīng zǐ xiàn', + '星宿海' => ' xīng xiù hǎi', + '量体温' => ' liáng tǐ wēn', + '切削面' => ' qiē xuē miàn', + '龙兴寺' => ' lóng xīng sì', + '想得开' => ' xiǎng de kāi', + '切削角' => ' qiē xuē jiǎo', + '量子化' => ' liàng zǐ huà', + '量子论' => ' liàng zǐ lùn', + '列女传' => ' liè nǚ zhuàn', + '怔神儿' => ' zhēng shén r', + '说得着' => ' shuō de zháo', + '水仙子' => ' shuǐ xiān zǐ', + '晒骆驼' => ' shài luò tuo', + '都江堰' => ' dū jiāng yàn', + '怪叔叔' => ' guài shū shu', + '说不了' => ' shuō bù liǎo', + '说不着' => ' shuō bù zháo', + '脑中风' => ' nǎo zhòng fēng', + '脑栓塞' => ' nǎo shuān sè', + '嚼舌头' => ' jiáo shé tou', + '更新世' => ' gēng xīn shì', + '乾隆帝' => ' qián lóng dì', + '更新版' => ' gēng xīn bǎn', + '均匀性' => ' jūn yún xìng', + '轻音乐' => ' qīng yīn yuè', + '切成丝' => ' qiē chéng sī', + '载客量' => ' zǎi kè liàng', + '控制杆' => ' kòng zhì gǎn', + '白娘子' => ' bái niáng zǐ', + '肋条肉' => ' lèi tiáo ròu', + '软龈音' => ' ruǎn yín yīn', + '软着陆' => ' ruǎn zhuó lù', + '垣曲县' => ' yuán qǔ xiàn', + '利眠宁' => ' lì mián nìng', + '嚼舌根' => ' jiáo shé gēn', + '南乡子' => ' nán xiāng zǐ', + '召陵区' => ' shào líng qū', + '重头戏' => ' chóng tóu xì', + '情急了' => ' qíng jí liǎo', + '切换到' => ' qiē huàn dào', + '重复节' => ' chóng fù jié', + '鲁甸县' => ' lǔ diàn xiàn', + '重眼皮' => ' chóng yǎn pí', + '可行性' => ' kě xíng xìng', + '鲗鱼涌' => ' zéi yú chōng', + '大黄素' => ' dài huáng sù', + '协调人' => ' xié tiáo rén', + '撑得住' => ' chēng de zhù', + '抽空机' => ' chōu kòng jī', + '表蒙子' => ' biǎo méng zǐ', + '热效应' => ' rè xiào yìng', + '文化圈' => ' wén huà juàn', + '四重唱' => ' sì chóng chàng', + '非对称' => ' fēi duì chèn', + '新娘子' => ' xīn niáng zǐ', + '应名儿' => ' yìng míng ér', + '原子能' => ' yuán zǐ néng', + '十三省' => ' shí sān xǐng', + '长恨歌' => ' cháng hèn gē', + '穷骨头' => ' qióng gú tou', + '反间谍' => ' fǎn jiàn dié', + '北斗星' => ' běi dǒu xīng', + '钱串儿' => ' qián chuàn r', + '受不了' => ' shòu bù liǎo', + '铺面房' => ' pū miàn fáng', + '纯音乐' => ' chún yīn yuè', + '磁效应' => ' cí xiào yìng', + '香子兰' => ' xiāng zǐ lán', + '马槟榔' => ' mǎ bīng lang', + '鹿角胶' => ' lù jiǎo jiāo', + '纯阳子' => ' chún yáng zǐ', + '生发油' => ' shēng fà yóu', + '操纵杆' => ' cāo zòng gǎn', + '九重霄' => ' jiǔ chóng xiāo', + '成方儿' => ' chéng fāng r', + '担担面' => ' dàn dɑn miàn', + '新干县' => ' xīn gān xiàn', + '抽冷子' => ' chōu lěng zǐ', + '长舌妇' => ' cháng shé fù', + '出差费' => ' chū chāi fèi', + '音乐院' => ' yīn yuè yuàn', + '处分权' => ' chǔ fèn quán', + '顶呱呱' => ' dǐng guā guā', + '双折射' => ' shuāng zhē shè', + '长乐市' => ' cháng lè shì', + '马生角' => ' mǎ shēng jué', + '斗南镇' => ' dǒu nán zhèn', + '应变力' => ' yìng biàn lì', + '灵雀寺' => ' líng qiǎo sì', + '曾庆红' => ' zēng qìng hóng', + '数九天' => ' shǔ jǐu tiān', + '闪亮儿' => ' shǎn liàng r', + '十天干' => ' shí tiān gān', + '冲劲儿' => ' chòng jìn er', + '汇出行' => ' huì chū háng', + '成都市' => ' chéng dū shì', + '衡量制' => ' héng liang zhì', + '长途车' => ' cháng tú chē', + '桑螵蛸' => ' sāng piāo xiāo', + '长葛市' => ' cháng gě shì', + '北斗镇' => ' běi dǒu zhèn', + '绿茸茸' => ' lǜ róng róng', + '曲颈甑' => ' qǔ jǐng zèng', + '山岗子' => ' shān gāng zǐ', + '身分证' => ' shēn fèn zhèng', + '博兴县' => ' bó xīng xiàn', + '打水漂' => ' dǎ shuǐ piāo', + '三娘子' => ' sān niáng zǐ', + '膀胱炎' => ' páng guāng yán', + '阿莲乡' => ' a lián xiāng', + '雄配子' => ' xíong pèi zǐ', + '人参果' => ' rén shēn guǒ', + '手指头' => ' shǒu zhí tou', + '吃枪子' => ' chī qiāng zǐ', + '上大夫' => ' shàng dài fū', + '电子层' => ' diàn zǐ céng', + '塞上曲' => ' sāi shàng qǔ', + '整脊学' => ' zhěng jǐ xué', + '闪长岩' => ' shǎn cháng yán', + '找不着' => ' zhǎo bu zháo', + '冲盹儿' => ' chòng dǔn er', + '电子管' => ' diàn zǐ guǎn', + '间谍罪' => ' jiàn dié zuì', + '中郎将' => ' zhōng láng jiàng', + '少女风' => ' shào nǚ fēng', + '门框子' => ' mén kuàng zi', + '数不上' => ' shǔ bù shàng', + '开拓性' => ' kāi tuò xìng', + '三勒浆' => ' sān lè jiāng', + '占地方' => ' zhàn dì fang', + '生查子' => ' shēng zhā zǐ', + '射流泵' => ' shè liú bèng', + '嘉兴市' => ' jiā xīng shì', + '时间差' => ' shí jiān chā', + '嘉荫县' => ' jiā yìn xiàn', + '钻空子' => ' zuān kòng zi', + '反应堆' => ' fǎn yìng duī', + '反应式' => ' fǎn yìng shì', + '反应锅' => ' fǎn yìng guō', + '着重号' => ' zhuó zhòng hào', + '反斜杠' => ' fǎn xié gàng', + '吹奏乐' => ' chuī zòu yuè', + '千佛洞' => ' qiān fó dòng', + '受难者' => ' shòu nàn zhě', + '随风倒' => ' suí fēng dǎo', + '双子叶' => ' shuāng zǐ yè', + '喘不过' => ' chuǎn bu guò', + '南长区' => ' nán cháng qū', + '打孔钻' => ' dǎ kǒng zuàn', + '难民营' => ' nàn mín yíng', + '难为情' => ' nán wéi qíng', + '扫帚菜' => ' sào zhǒu cài', + '隆子县' => ' lóng zǐ xiàn', + '阳电荷' => ' yáng diàn hè', + '阳电子' => ' yáng diàn zǐ', + '阳曲县' => ' yáng qǔ xiàn', + '肠杆菌' => ' cháng gǎn jūn', + '砷中毒' => ' shēn zhòng dú', + '量子态' => ' liàng zǐ tài', + '漂流瓶' => ' piāo liú píng', + '切换键' => ' qiē huàn jiàn', + '小娘子' => ' xiǎo niáng zǐ', + '闹嚷嚷' => ' nào rāng rɑng', + '横切面' => ' héng qiē miàn', + '创可贴' => ' chuāng kě tiē', + '长顺县' => ' cháng shùn xiàn', + '粘土砖' => ' nián tǔ zhuān', + '将进酒' => ' qiāng jìn jiǔ', + '轴对称' => ' zhóu duì chèn', + '相扑手' => ' xiàng pū shǒu', + '哮喘病' => ' xiào chuǎn bìng', + '娘子关' => ' niáng zǐ guān', + '两重天' => ' liǎng chóng tiān', + '复兴乡' => ' fù xīng xiāng', + '两重性' => ' liǎng chóng xìng', + '晕血症' => ' yùn xuè zhèng', + '白相人' => ' bái xiàng rén', + '长颈瓶' => ' cháng jǐng píng', + '卷筒纸' => ' juàn tǒng zhǐ', + '假芫茜' => ' jiǎ yuán qiàn', + '万圣节' => ' wàn shèng jiē', + '种植者' => ' zhòng zhí zhě', + '长颈龙' => ' cháng jǐng lóng', + '调节表' => ' tiáo jié biǎo', + '荐头店' => ' jiàn tou diàn', + '调味料' => ' tiáo wèi liào', + '数得上' => ' shǔ děi shàng', + '上齿龈' => ' shàng chǐ yín', + '长方形' => ' cháng fāng xíng', + '吹管乐' => ' chuī guǎn yuè', + '走为上' => ' zǒu wéi shàng', + '溜溜转' => ' liū liū zhuàn', + '重身子' => ' chóng shēn zi', + '超对称' => ' chāo duì chèn', + '子宫腔' => ' zǐ gōng qiāng', + '未命名' => ' wèi mìng míng', + '重覆性' => ' chóng fù xìng', + '乾清宫' => ' qián qīng gōng', + '相应物' => ' xiāng yìng wù', + '太行山' => ' tài háng shān', + '种牛痘' => ' zhòng niú dòu', + '众生相' => ' zhòng shēng xiàng', + '长明灯' => ' cháng míng dēng', + '闹哄哄' => ' nào hōng hǒng', + '星相图' => ' xīng xiàng tú', + '量尺寸' => ' liáng chǐ cùn', + '调节税' => ' tiáo jié shuì', + '调停者' => ' tiáo tíng zhě', + '伽南香' => ' qié nán xiāng', + '轰隆隆' => ' hōng lōng lóng', + '洪洞县' => ' hóng tóng xiàn', + '朴正熙' => ' piáo zhèng xī', + '冗长度' => ' rǒng cháng dù', + '救难船' => ' jiù nàn chuán', + '兴国县' => ' xīng guó xiàn', + '退行性' => ' tuì xíng xìng', + '换档杆' => ' huàn dàng gǎn', + '分散相' => ' fēn sàn xiàng', + '兴隆台' => ' xīng lóng tái', + '长毛象' => ' cháng máo xiàng', + '毛茸茸' => ' máo róng róng', + '长汀县' => ' cháng tīng xiàn', + '东兴市' => ' dōng xīng shì', + '东三省' => ' dōng sān xǐng', + '长治乡' => ' cháng zhì xiāng', + '扬子江' => ' yáng zǐ jiāng', + '保险杠' => ' bǎo xiǎn gàng', + '豆豉酱' => ' dòu chǐ jiàng', + '灰蒙蒙' => ' huī mēng méng', + '长滨乡' => ' cháng bīn xiāng', + '黄埔港' => ' huáng pǔ gǎng', + '酸中毒' => ' suān zhòng dú', + '长生果' => ' cháng shēng guǒ', + '长流水' => ' cháng liú shuǐ', + '进行性' => ' jìn xíng xìng', + '兴海县' => ' xīng hǎi xiàn', + '豁免权' => ' huò miǎn quán', + '同字框' => ' tóng zì kuàng', + '电子秤' => ' diàn zǐ chèng', + '排行榜' => ' pái háng bǎng', + '林甸县' => ' lín diàn xiàn', + '水浒传' => ' shuǐ hǔ zhuàn', + '卷叶虫' => ' juàn yè chóng', + '卷轴装' => ' juàn zhóu zhuāng', + '红娘子' => ' hóng niáng zǐ', + '元长乡' => ' yuán cháng xiāng', + '轧钢条' => ' zhá gāng tiáo', + '膀胱镜' => ' páng guāng jìng', + '弹簧板' => ' tán huáng bǎn', + '酆都城' => ' fēng dū chéng', + '川滇藏' => ' chuān diān zàng', + '兴宁市' => ' xīng níng shì', + '电转儿' => ' diàn zhuàn ér', + '致良知' => ' zhì liáng zhī', + '运动员' => ' yùn dòng yuán', + '拖累症' => ' tuō lěi zhèng', + '兴平市' => ' xīng píng shì', + '扫帚星' => ' sào zhǒu xīng', + '九转丹' => ' jiǔ zhuàn dān', + '甲壳虫' => ' jiǎ qiào chóng', + '兴文县' => ' xīng wén xiàn', + '龈脓肿' => ' yín nóng zhǒng', + '转速表' => ' zhuàn sù biǎo', + '快中子' => ' kuài zhōng zǐ', + '适应性' => ' shì yìng xìng', + '金刚钻' => ' jīn gāng zuàn', + '正仓院' => ' zhēng cāng yuàn', + '调整环' => ' tiáo zhěng huán', + '海监船' => ' hǎi jiàn chuán', + '航行灯' => ' háng xíng dēng', + '厚生相' => ' hòu shēng xiàng', + '霰弹枪' => ' xiàn dàn qiāng', + '转动轴' => ' zhuàn dòng zhóu', + '重正化' => ' chóng zhèng huà', + '狂想曲' => ' kuáng xiǎng qǔ', + '广成子' => ' guǎng chéng zǐ', + '中间件' => ' zhōng jiān jiàn', + '娘娘腔' => ' niáng niang qiāng', + '绷场面' => ' bēng chǎng miàn', + '长镜头' => ' cháng jìng tóu', + '转动件' => ' zhuàn dòng jiàn', + '公平秤' => ' gōng píng chèng', + '花生浆' => ' huā shēng jiàng', + '生还者' => ' shēng huán zhě', + '中长跑' => ' zhōng cháng pǎo', + '三重县' => ' sān chóng xiàn', + '颈椎病' => ' jǐng zhuī bìng', + '清劲风' => ' qīng jìng fēng', + '钻井工' => ' zuàn jǐng gōng', + '工段长' => ' gōng duàn cháng', + '少壮派' => ' shào zhuàng pài', + '双生子' => ' shuāng shēng zǐ', + '审判长' => ' shěn pàn cháng', + '绷子床' => ' bēng zi chuáng', + '黄长烨' => ' huáng cháng yè', + '正长石' => ' zhèng cháng shí', + '青藏线' => ' qīng zàng xiàn', + '长长的' => ' cháng cháng de', + '中标者' => ' zhòng biāo zhě', + '相对象' => ' xiàng duì xiàng', + '左丞相' => ' zuǒ chéng xiàng', + '照相馆' => ' zhào xiàng guǎn', + '长绒棉' => ' cháng róng mián', + '长寿面' => ' cháng shòu miàn', + '老框框' => ' lǎo kuàng kuàng', + '清算行' => ' qīng suàn háng', + '电转盘' => ' diàn zhuàn pán', + '宽甸县' => ' kuān diàn xiàn', + '供应商' => ' gōng yìng shāng', + '香獐子' => ' xiāng zhāng zǐ', + '正当性' => ' zhèng dàng xìng', + '上半晌' => ' shàng bàn shǎng', + '命令行' => ' mìng lìng háng', + '行情表' => ' háng qíng biǎo', + '上将军' => ' shàng jiàng jūn', + '前首相' => ' qián shǒu xiàng', + '娘家姓' => ' niáng jia xìng', + '沉甸甸' => ' chén diàn diàn', + '中都城' => ' zhōng dū chéng', + '团团转' => ' tuán tuán zhuàn', + '黄克强' => ' huáng kè jiàng', + '应声虫' => ' yìng shēng chóng', + '车头相' => ' chē tóu xiàng', + '总长度' => ' zǒng cháng dù', + '曾荫权' => ' zēng yìn quán', + '强的松' => ' qiáng dí sōng', + '面包片' => ' miàn bāo piān', + '照相机' => ' zhào xiàng jī', + '摔跟头' => ' shuāi gēn tou', + '炸酱面' => ' zhá jiàng miàn', + '长宁县' => ' cháng níng xiàn', + '铅中毒' => ' qiān zhòng dú', + '喜相逢' => ' xǐ xiàng féng', + '佛跳墙' => ' fó tiào qiáng', + '青少年' => ' qīng shào nián', + '肖像权' => ' xiāo xiàng quán', + '长岭县' => ' cháng lǐng xiàn', + '黑旋风' => ' hēi xuàn fēng', + '纵切面' => ' zòng qiē miàn', + '相片儿' => ' xiàng piān er', + '田长霖' => ' tián cháng lín', + '干事长' => ' gàn shi zhǎng', + '漂白水' => ' piǎo bái shuǐ', + '重婚罪' => ' chóng hūn zuì', + '拉长脸' => ' lā cháng liǎn', + '校书郎' => ' jiào shū láng', + '楞怔怔' => ' léng zhèng zhèng', + '幻想曲' => ' huàn xiǎng qǔ', + '着火点' => ' zháo huǒ diǎn', + '吃空饷' => ' chī kòng xiǎng', + '青囊经' => ' qīng náng jīng', + '还原糖' => ' huán yuán táng', + '光反应' => ' guāng fǎn yìng', + '白晃晃' => ' bái huàng huǎng', + '范长江' => ' fàn cháng jiāng', + '照相版' => ' zhào xiàng bǎn', + '照相术' => ' zhào xiàng shù', + '中甸县' => ' zhōng diàn xiàn', + '黄萎病' => ' huáng wěi bìng', + '定兴县' => ' dìng xīng xiàn', + '测量船' => ' cè liáng chuán', + '灭虫宁' => ' miè chóng nìng', + '相空间' => ' xiàng kōng jiān', + '荥经县' => ' yíng jīng xiàn', + '农场主' => ' nóng cháng zhǔ', + '小公共' => ' xiǎo gōng gòng', + '敲丧钟' => ' qiāo sāng zhōng', + '长垣县' => ' cháng yuán xiàn', + '氧效应' => ' yǎng xiào yìng', + '中圈套' => ' zhòng quān tào', + '沧浪亭' => ' cāng láng tíng', + '教书匠' => ' jiāo shū jiàng', + '照相纸' => ' zhào xiàng zhǐ', + '长寿菜' => ' cháng shòu cài', + '枞阳县' => ' zōng yáng xiàn', + '换挡杆' => ' huàn dǎng gǎn', + '川党参' => ' chuān dǎng shēn', + '中毒性' => ' zhòng dú xìng', + '哑终端' => ' yā zhōng duān', + '长野县' => ' cháng yě xiàn', + '枕头风' => ' zhěn tou fēng', + '北朝鲜' => ' běi cháo xiǎn', + '公仔面' => ' gōng zǎi miàn', + '弦切角' => ' xián qiē jiǎo', + '病假条' => ' bìng jià tiáo', + '张国焘' => ' zhāng guó tāo', + '眼干症' => ' yǎn gān zhèng', + '对称轴' => ' duì chèn zhóu', + '挑战者' => ' tiǎo zhàn zhě', + '相位差' => ' xiàng wèi chā', + '长颈鹿' => ' cháng jǐng lù', + '相似性' => ' xiāng sì xìng', + '光电子' => ' guāng diàn zǐ', + '对称性' => ' duì chèn xìng', + '瞭望台' => ' liào wàng tái', + '小脏鬼' => ' xiǎo zāng guǐ', + '曾国荃' => ' zēng guó quán', + '对话框' => ' duì huà kuàng', + '蒙蒙黑' => ' mēng mēng hēi', + '占星师' => ' zhān xīng shī', + '衣冠冢' => ' yì guān zhǒng', + '星相术' => ' xīng xiàng shù', + '椎间盘' => ' zhuī jiān pán', + '空调车' => ' kōng tiáo chē', + '占星家' => ' zhān xīng jiā', + '长筒袜' => ' cháng tǒng wà', + '子长县' => ' zǐ cháng xiàn', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/data/words_1 b/lib/vendor/overtrue/pinyin/data/words_1 new file mode 100644 index 0000000000..e8d3bebc61 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_1 @@ -0,0 +1,8003 @@ + ' liáng yóu chǐ', + '二重性' => ' èr chóng xìng', + '长臂猿' => ' cháng bì yuán', + '正规化' => ' zhèng guī huā', + '创伤后' => ' chuāng shāng hòu', + '长统袜' => ' cháng tǒng wà', + '应战书' => ' yìng zhàn shū', + '重定向' => ' chóng dìng xiàng', + '扁担星' => ' biǎn dàn xīng', + '交白卷' => ' jiāo bái juàn', + '应用层' => ' yìng yòng céng', + '朝鲜文' => ' cháo xiǎn wén', + '穷酸相' => ' qíong suān xiàng', + '正电荷' => ' zhèng diàn hè', + '见识浅' => ' jiàn shi qiǎn', + '冲孔机' => ' chòng kǒng jī', + '空调室' => ' kōng tiáo shì', + '原子钟' => ' yuán zǐ zhōng', + '空白点' => ' kòng bái diǎn', + '光散射' => ' guāng sǎn shè', + '碱中毒' => ' jiǎn zhòng dú', + '兴冲冲' => ' xīng chōng chōng', + '薯莨绸' => ' shǔ liáng chóu', + '占星术' => ' zhān xīng shù', + '丧葬费' => ' sāng zàng fèi', + '短波长' => ' duǎn bō cháng', + '南北长' => ' nán běi cháng', + '协调员' => ' xié tiáo yuán', + '最前面' => ' zuì qián mian', + '中子星' => ' zhōng zǐ xīng', + '少年犯' => ' shào nián fàn', + '公切线' => ' gōng qiē xiàn', + '知更鸟' => ' zhī gēng niǎo', + '膀胱癌' => ' páng guāng ái', + '转轮王' => ' zhuàn lún wáng', + '江城子' => ' jiāng chéng zǐ', + '汞中毒' => ' gǒng zhòng dú', + '南朝鲜' => ' nán cháo xiǎn', + '长蛇阵' => ' cháng shé zhèn', + '二重唱' => ' èr chóng chàng', + '长统靴' => ' cháng tǒng xuē', + '双子座' => ' shuāng zǐ zuò', + '少女峰' => ' shào nǔ: fēng', + '强迫性' => ' qiǎng pò xìng', + '公冶长' => ' gōng yě cháng', + '载畜量' => ' zǎi chù liàng', + '中爪哇' => ' zhōng zhǎo wā', + '中洋脊' => ' zhōng yáng jǐ', + '再加上' => ' zài jiā shang', + '中子源' => ' zhōng zǐ yuán', + '复选框' => ' fù xuǎn kuàng', + '挑大梁' => ' tiǎo dà liáng', + '弹簧管' => ' tán huáng guǎn', + '占星学' => ' zhān xīng xué', + '小便斗' => ' xiǎo biàn dǒu', + '三连冠' => ' sān lián guàn', + '冲击钻' => ' chōng jī zuàn', + '中奖者' => ' zhòng jiǎng zhě', + '散兵线' => ' sǎn bīng xiàn', + '打长工' => ' dǎ cháng gōng', + '三重门' => ' sān chóng mén', + '标准差' => ' biāo zhǔn chā', + '相平面' => ' xiàng píng miàn', + '还乡团' => ' huán xiāng tuán', + '长治县' => ' cháng zhì xiàn', + '朝阳门' => ' zhāo yáng mén', + '长沙县' => ' cháng shā xiàn', + '长须鲸' => ' cháng xū jīng', + '小数点' => ' xiǎo shǔ diǎn', + '茄萣乡' => ' qié dìng xiāng', + '旁切圆' => ' páng qiē yuán', + '够得上' => ' gòu děi shàng', + '卷层云' => ' juàn céng yún', + '长白镇' => ' cháng bái zhèn', + '敲竹杠' => ' qiāo zhū gàng', + '散兵坑' => ' sǎn bīng kēng', + '碰头会' => ' pèng tóu kuài', + '乔冠华' => ' qiáo guān huà', + '长蛇座' => ' cháng shé zuò', + '挑战书' => ' tiǎo zhàn shū', + '转车台' => ' zhuàn chē tái', + '还原酶' => ' huán yuán méi', + '不相称' => ' bù xiāng chèn', + '丹参酮' => ' dān shēn tóng', + '三重市' => ' sān chóng shì', + '能量子' => ' néng liàng zǐ', + '都昌县' => ' dū chāng xiàn', + '切向量' => ' qiē xiàng liàng', + '长毛绒' => ' cháng máo róng', + '三重奏' => ' sān chóng zòu', + '线桄子' => ' xiàn guàng zi', + '供应品' => ' gōng yìng pǐn', + '李长春' => ' lǐ cháng chūn', + '涡阳县' => ' guō yáng xiàn', + '供应室' => ' gōng yìng shì', + '拓荒者' => ' tuò huāng zhě', + '兴奋性' => ' xīng fèn xìng', + '右丞相' => ' yòu chéng xiàng', + '弓长岭' => ' gōng cháng lǐng', + '缝纫工' => ' féng rèn gōng', + '一年生' => ' yì nián shēng', + '自转轴' => ' zì zhuàn zhóu', + '油晃晃' => ' yóu huàng huǎng', + '天台宗' => ' tiān tāi zōng', + '切平面' => ' qiē píng miàn', + '长丰县' => ' cháng fēng xiàn', + '电子枪' => ' diàn zǐ qiāng', + '辉长岩' => ' huī cháng yán', + '性兴奋' => ' xìng xīng fèn', + '行香子' => ' xíng xiāng zǐ', + '链反应' => ' liàn fǎn yìng', + '传记片' => ' zhuàn jì piàn', + '供应者' => ' gōng yìng zhě', + '着陆场' => ' zhuó lù chǎng', + '着眼点' => ' zhuó yǎn diǎn', + '怪念头' => ' guài niàn tou', + '大城市' => ' dài chéng shì', + '性行为' => ' xìng xíng wéi', + '黑糁糁' => ' hēi shēn shēn', + '长命锁' => ' cháng mìng suǒ', + '刀削面' => ' dāo xiāo miàn', + '游说团' => ' yóu shuì tuán', + '性偏好' => ' xìng piān hào', + '长兴县' => ' cháng xīng xiàn', + '长角羊' => ' cháng jiǎo yáng', + '弹着点' => ' dàn zhuó diǎn', + '天台山' => ' tiān tāi shān', + '冷轧钢' => ' lěng zhá gāng', + '廊坊市' => ' láng fáng shì', + '酌处权' => ' zhuó chǔ quán', + '永兴县' => ' yǒng xīng xiàn', + '混水墙' => ' hún shuǐ qiáng', + '转一趟' => ' zhuàn yī tàng', + '弹簧销' => ' tán huáng xiāo', + '萧万长' => ' xiāo wàn cháng', + '长泰县' => ' cháng tài xiàn', + '霰粒肿' => ' xiàn lì zhǒng', + '寻甸县' => ' xún diàn xiàn', + '戳脊梁' => ' chuō jǐ liang', + '蛮漂亮' => ' mán piào liang', + '洋中脊' => ' yáng zhōng jǐ', + '有粘性' => ' yǒu nián xìng', + '弹簧床' => ' tán huáng chuáng', + '长城站' => ' cháng chéng zhàn', + '长海县' => ' cháng hǎi xiàn', + '开小差' => ' kāi xiǎo chāi', + '朝鲜人' => ' cháo xiǎn rén', + '间接税' => ' jiàn jiē shuì', + '内省性' => ' nèi xǐng xìng', + '挑逗性' => ' tiǎo dòu xìng', + '空白表' => ' kòng bái biǎo', + '福兴乡' => ' fú xīng xiāng', + '照相簿' => ' zhào xiàng bù', + '白蛇传' => ' bái shé zhuàn', + '咸兴市' => ' xián xīng shì', + '星相师' => ' xīng xiàng shī', + '关卡税' => ' guān qiǎ shuì', + '弧线长' => ' hú xiàn cháng', + '原子量' => ' yuán zǐ liàng', + '罗盛教' => ' luó chéng jiào', + '手相学' => ' shǒu xiàng xué', + '放大率' => ' fàng dà shuài', + '公羊传' => ' gōng yáng zhuàn', + '弹性销' => ' tán xìng xiāo', + '铜管乐' => ' tóng guǎn yuè', + '还原焰' => ' huán yuán yàn', + '烹调术' => ' pēng tiáo shù', + '切空间' => ' qiē kōng jiān', + '凉州曲' => ' liáng zhōu qǔ', + '三框栏' => ' sān kuàng lán', + '弹簧秤' => ' tán huáng chèng', + '朝鲜筝' => ' cháo xiǎn zhēng', + '兴仁县' => ' xīng rén xiàn', + '相似形' => ' xiāng sì xíng', + '星相学' => ' xīng xiàng xué', + '间歇泉' => ' jiàn xiē quán', + '扇面琴' => ' shān miàn qín', + '间谍网' => ' jiàn dié wǎng', + '电荷量' => ' diàn hè liàng', + '见世面' => ' xiàn shì miàn', + '称之为' => ' chēng zhī wéi', + '长白县' => ' cháng bái xiàn', + '称多县' => ' chèn duō xiàn', + '长白山' => ' cháng bái shān', + '长生殿' => ' cháng shēng diàn', + '长生天' => ' cháng shēng tiān', + '重阳节' => ' chóng yáng jié', + '曲周县' => ' qǔ zhōu xiàn', + '随想曲' => ' suí xiǎng qǔ', + '乡人子' => ' xiāng rén zǐ', + '宅度假' => ' zhái dù jià', + '吃馆子' => ' chī guǎn zǐ', + '打长途' => ' dǎ cháng tú', + '奏鸣曲' => ' zòu míng qǔ', + '福鼎市' => ' fú dǐng shì', + '钢琴曲' => ' gāng qín qǔ', + '子宫炎' => ' zǐ gōng yán', + '背带裙' => ' bēi dài qún', + '雪佛龙' => ' xuě fó lóng', + '笑脸儿' => ' xiào liǎn r', + '高挑儿' => ' gāo tiǎo ér', + '舍身崖' => ' shè shēn yá', + '水饺儿' => ' shuǐ jiǎo r', + '找不到' => ' zhǎo bu dào', + '数来宝' => ' shǔ lái bǎo', + '祭司长' => ' jì sī cháng', + '数不清' => ' shǔ bù qīng', + '区字框' => ' qū zì kuàng', + '长鼻目' => ' cháng bí mù', + '所得税' => ' suǒ de shuì', + '穆棱市' => ' mù líng shì', + '子母钟' => ' zǐ mǔ zhōng', + '油炸鬼' => ' yóu zhá guǐ', + '妃子笑' => ' fēi zǐ xiào', + '牛头刨' => ' niú tóu bào', + '水处理' => ' shuǐ chǔ lǐ', + '吃干饭' => ' chī gān fàn', + '福清市' => ' fú qīng shì', + '哀伤地' => ' āi shāng de', + '卷铺盖' => ' juǎn pū gài', + '印子钱' => ' yìn zǐ qián', + '筋斗云' => ' jīn dǒu yún', + '冲压机' => ' chòng yā jī', + '斗六市' => ' dǒu lìu shì', + '半吊子' => ' bàn diào zǐ', + '漂白剂' => ' piǎo bái jì', + '有分寸' => ' yǒu fēn cun', + '单老师' => ' shàn lǎo shī', + '杂和面' => ' zá huo miàn', + '农家子' => ' nóng jiā zǐ', + '傍角儿' => ' bàng jué ér', + '江西腊' => ' jiāng xī là', + '不干净' => ' bù gān jìng', + '干燥窑' => ' gān zào yáo', + '硬骨头' => ' yìng gú tou', + '皮划艇' => ' pí huá tǐng', + '干燥室' => ' gān zào shì', + '麻纤维' => ' mā xiān wéi', + '福州市' => ' fú zhōu shì', + '爪哇国' => ' zhǎo wā guó', + '切成块' => ' qiē chéng kuài', + '手腕子' => ' shǒu wàn zǐ', + '四方台' => ' sì fāng tái', + '应力值' => ' yìng lì zhí', + '福泉市' => ' fú quán shì', + '子程序' => ' zǐ chéng xù', + '烘干器' => ' hōng gān qì', + '软骨头' => ' ruǎn gú tou', + '原子束' => ' yuán zǐ shù', + '差一点' => ' chà yì diǎn', + '发横财' => ' fā hèng cái', + '感应器' => ' gǎn yìng qì', + '尥蹶子' => ' liào jué zǐ', + '善男子' => ' shàn nán zǐ', + '什刹海' => ' shí chà hǎi', + '校验器' => ' jiào yàn qì', + '露一手' => ' lòu yī shǒu', + '少年宫' => ' shào nián gōng', + '工尺谱' => ' gōng chě pǔ', + '阴电子' => ' yīn diàn zǐ', + '发现号' => ' fā xiàn háo', + '处理掉' => ' chǔ lǐ diào', + '扎猛子' => ' zhā měng zǐ', + '人缘儿' => ' rén yuán ér', + '原子弹' => ' yuán zǐ dàn', + '扎线带' => ' zā xiàn dài', + '原子堆' => ' yuán zǐ duī', + '脚腕子' => ' jiǎo wàn zǐ', + '寻开心' => ' xín kāi xīn', + '原子时' => ' yuán zǐ shí', + '人影儿' => ' rén yǐng ér', + '旁边儿' => ' páng biān r', + '什件儿' => ' shí jiàn ér', + '早知道' => ' zǎo zhī dao', + '陈子昂' => ' chén zǐ áng', + '咽鼓管' => ' yān gǔ guǎn', + '散文诗' => ' sǎn wén shī', + '孢子囊' => ' bāo zǐ náng', + '开拓者' => ' kāi tuò zhě', + '水磨沟' => ' shuǐ mò gōu', + '扫把星' => ' sào bǎ xīng', + '屎壳郎' => ' shǐ ke làng', + '戳得住' => ' chuō de zhù', + '间歇热' => ' jiàn xiē rè', + '战斗部' => ' zhàn dǒu bù', + '刮削器' => ' guā xiāo qì', + '章子怡' => ' zhāng zǐ yí', + '张僧繇' => ' zhāng sēng yóu', + '煤斗车' => ' méi dǒu chē', + '粘土岩' => ' nián tǔ yán', + '童子军' => ' tóng zǐ jūn', + '报纸夹' => ' bào zhǐ jiá', + '秒差距' => ' miǎo chā jù', + '闵行区' => ' mǐn háng qū', + '间隔号' => ' jiàn gé hào', + '兵油子' => ' bīng yóu zǐ', + '盘杠子' => ' pán gàng zi', + '梅干菜' => ' méi gān cài', + '女神蛤' => ' nǔ: shén gé', + '长距离' => ' cháng jù lí', + '间奏曲' => ' jiàn zòu qǔ', + '蚰蜒草' => ' yóu dàn cǎo', + '干着急' => ' gān zháo jí', + '集电杆' => ' jí diàn gǎn', + '好事者' => ' hào shì zhě', + '五苓散' => ' wǔ líng sǎn', + '架秧子' => ' jià yāng zǐ', + '甩负荷' => ' shuǎi fù hè', + '顶尖儿' => ' dǐng jiān r', + '佛手瓜' => ' fó shǒu guā', + '乐学者' => ' yuè xué zhě', + '畜产品' => ' xù chǎn pǐn', + '番茄汁' => ' fān qié zhī', + '片儿会' => ' piān er huì', + '大龙湫' => ' dà lóng qiū', + '捅娄子' => ' tǒng lóu zǐ', + '看门人' => ' kān mén rén', + '太子港' => ' tài zǐ gǎng', + '淋溶土' => ' lìn róng tǔ', + '脊椎炎' => ' jǐ zhuī yán', + '种植园' => ' zhòng zhí yuán', + '澎湖岛' => ' péng hú dǎo', + '码长城' => ' mǎ cháng chéng', + '剪切力' => ' jiǎn qiē lì', + '扛长工' => ' káng cháng gōng', + '小舅子' => ' xiǎo jiù zǐ', + '肠阻塞' => ' cháng zǔ sè', + '过得硬' => ' guò de yìng', + '剪头发' => ' jiǎn tóu fa', + '肋间肌' => ' lèi jiān jī', + '朝阳区' => ' cháo yáng qū', + '拗口令' => ' ào kǒu lìng', + '打折票' => ' dǎ shé piào', + '打麻将' => ' dǎ má jiàng', + '氧分子' => ' yǎng fēn zǐ', + '眼见得' => ' yǎn jiàn de', + '蒙蒙亮' => ' méng mēng liàng', + '翘拇指' => ' qiáo mǔ zhǐ', + '间断性' => ' jiàn duàn xìng', + '看不见' => ' kàn bú jiàn', + '看不懂' => ' kàn bu dǒng', + '抹灰层' => ' mò huī céng', + '漏斗云' => ' lòu dǒu yún', + '疏勒县' => ' shū lè xiàn', + '核反应' => ' hé fǎn yìng', + '金国汗' => ' jīn guó hán', + '复兴社' => ' fù xīng shè', + '室内乐' => ' shì nèi yuè', + '铺盖卷' => ' pū gài juǎn', + '要不了' => ' yào bù liǎo', + '易卜生' => ' yì bǔ shēng', + '占卜者' => ' zhān bǔ zhě', + '何应钦' => ' hé yìng qīn', + '大娘子' => ' dà niáng zǐ', + '散文家' => ' sǎn wén jiā', + '听不到' => ' tīng bu dào', + '真是的' => ' zhēn shi de', + '淋球菌' => ' lìn qíu jūn', + '柔佛州' => ' róu fó zhōu', + '顺手儿' => ' shùn shǒu r', + '留成儿' => ' líu chéng r', + '检察长' => ' jiǎn chá cháng', + '甲壳素' => ' jiǎ qiào sù', + '直贡呢' => ' zhí gòng ní', + '五虎将' => ' wǔ hǔ jiàng', + '半彪子' => ' bàn biāo zǐ', + '太子党' => ' tài zǐ dǎng', + '音乐家' => ' yīn yuè jiā', + '博白县' => ' bó bái xiàn', + '佛山市' => ' fó shān shì', + '树行子' => ' shù hàng zi', + '数得着' => ' shǔ de zháo', + '重复法' => ' chóng fù fǎ', + '夫妻相' => ' fū qī xiàng', + '韦应物' => ' wéi yìng wù', + '家雀儿' => ' jiā qiǎo ér', + '贼忒忒' => ' zéi tuī tuī', + '韛拐子' => ' bài guǎi zǐ', + '副反应' => ' fù fǎn yìng', + '笨家伙' => ' bèn jiā huo', + '数不着' => ' shǔ bù zháo', + '露头角' => ' lù tóu jiǎo', + '包干制' => ' bāo gān zhì', + '赤松子' => ' chì sōng zǐ', + '应景儿' => ' yìng jǐng r', + '管扳子' => ' guǎn bān zǐ', + '乱哄哄' => ' luàn hǒng hǒng', + '私生子' => ' sī shēng zǐ', + '管乐器' => ' guǎn yuè qì', + '剪切机' => ' jiǎn qiē jī', + '宜兴市' => ' yí xīng shì', + '音乐会' => ' yīn yuè huì', + '大还丹' => ' dà huán dān', + '消闲儿' => ' xiāo xián r', + '重离子' => ' zhòng lí zǐ', + '耍骨头' => ' shuǎ gú tou', + '耍笔杆' => ' shuǎ bǐ gǎn', + '看花眼' => ' kān huā yǎn', + '采血针' => ' cǎi xiě zhēn', + '撑得慌' => ' chēng de huāng', + '车前子' => ' chē qián zǐ', + '决明子' => ' jué míng zǐ', + '核门槛' => ' hé mén jiàn', + '老爷岭' => ' lǎo ye lǐng', + '知识界' => ' zhī shi jiè', + '鬼点子' => ' guǐ diǎn zǐ', + '短打扮' => ' duǎn dǎ ban', + '一边倒' => ' yī biān dǎo', + '打晃儿' => ' dǎ huàng er', + '惠更斯' => ' huì gēng sī', + '野颠茄' => ' yě diān qié', + '差异性' => ' chā yì xìng', + '翻跟头' => ' fān gēn tou', + '翻跟斗' => ' fān gēn dǒu', + '刘少奇' => ' liú shào qí', + '打工仔' => ' dǎ gōng zǎi', + '刘涓子' => ' líu juān zǐ', + '重活儿' => ' zhòng huó r', + '音乐学' => ' yīn yuè xué', + '旋风装' => ' xuàn fēng zhuāng', + '音乐节' => ' yīn yuè jié', + '悲切切' => ' bēi qiè qiē', + '绮想曲' => ' qǐ xiǎng qǔ', + '淮南子' => ' huái nán zǐ', + '放包袱' => ' fàng bāo fú', + '反应炉' => ' fǎn yìng lú', + '较真儿' => ' jiào zhēn r', + '草垫子' => ' cǎo diàn zǐ', + '反应器' => ' fǎn yìng qì', + '反应热' => ' fǎn yìng rè', + '冷处理' => ' lěng chǔ lǐ', + '高低杠' => ' gāo dī gàng', + '不协调' => ' bù xié tiáo', + '反应物' => ' fǎn yìng wù', + '娘儿们' => ' niáng r men', + '协调器' => ' xié tiáo qì', + '茄红素' => ' qié hóng sù', + '软耳朵' => ' ruǎn ěr duo', + '复兴门' => ' fù xīng mén', + '叫花子' => ' jiào huā zǐ', + '倒胃口' => ' dǎo wèi kǒu', + '李娃传' => ' lǐ wá zhuàn', + '男人家' => ' nán rén jia', + '刹那间' => ' chà nà jiān', + '闹别扭' => ' nào biè niǔ', + '和面机' => ' huó miàn jī', + '分子筛' => ' fèn zǐ shāi', + '书卷气' => ' shū juàn qì', + '切菜板' => ' qiē cài bǎn', + '牛肉干' => ' niú ròu gān', + '番茄粉' => ' fān qié fěn', + '不划算' => ' bù huá suàn', + '切分音' => ' qiē fēn yīn', + '调节阀' => ' tiáo jié fá', + '调音器' => ' tiáo yīn qì', + '耳光子' => ' ěr guāng zǐ', + '烂舌头' => ' làn shé tou', + '调谐器' => ' tiáo xié qì', + '猪仔包' => ' zhū zǎi bāo', + '着边儿' => ' zháo biān r', + '爪哇岛' => ' zhǎo wā dǎo', + '钟子期' => ' zhōng zǐ qī', + '调温器' => ' tiáo wēn qì', + '倒霉蛋' => ' dǎo méi dàn', + '鱼子酱' => ' yú zǐ jiàng', + '多菲什' => ' duō fēi shí', + '军乐队' => ' jūn yuè duì', + '小崽子' => ' xiǎo zǎi zǐ', + '小石子' => ' xiǎo shí zǐ', + '掺沙子' => ' chān shā zi', + '小叔子' => ' xiǎo shū zǐ', + '不倒翁' => ' bù dǎo wēng', + '更衣室' => ' gēng yī shì', + '逍遥子' => ' xiāo yáo zǐ', + '叫化子' => ' jiào huā zi', + '歪点子' => ' wāi diǎn zǐ', + '反应力' => ' fǎn yìng lì', + '轧钢机' => ' zhá gāng jī', + '切削机' => ' qiē xiāo jī', + '切断机' => ' qiē duàn jī', + '挑担子' => ' tiāo dàn zi', + '变速杆' => ' biàn sù gǎn', + '碾磙子' => ' niǎn gǔn zǐ', + '动载荷' => ' dòng zài hè', + '伤和气' => ' shāng hé qi', + '两头儿' => ' liǎng tóu r', + '角斗士' => ' jué dòu shì', + '看门狗' => ' kān mén gǒu', + '无为县' => ' wú wéi xiàn', + '解痉剂' => ' xiè jìng jì', + '弹射出' => ' tán shè chū', + '三都县' => ' sān dū xiàn', + '月氏人' => ' yuè zhī rén', + '瓦岗军' => ' wǎ gāng jūn', + '口角炎' => ' kǒu jué yán', + '蚌埠市' => ' bèng bù shì', + '处女航' => ' chǔ nǚ háng', + '看家狗' => ' kān jiā gǒu', + '月收入' => ' yuè shōu rù', + '催眠曲' => ' cuī mián qǔ', + '蔡侯纸' => ' cài hòu zhǐ', + '蜚蠊科' => ' fěi lián kē', + '弹球盘' => ' tán qíu pán', + '压倒性' => ' yā dǎo xìng', + '胃粘膜' => ' wèi nián mó', + '未见得' => ' wèi jiàn de', + '被没收' => ' bèi mò shōu', + '都察院' => ' dū chá yuàn', + '采桑子' => ' cǎi sāng zǐ', + '抗倒伏' => ' kàng dǎo fú', + '翻斗车' => ' fān dǒu chē', + '天可汗' => ' tiān kè hán', + '切换阀' => ' qiē huàn fá', + '小人儿' => ' xiǎo rén er', + '小妹子' => ' xiǎo mèi zǐ', + '几丁质' => ' jī dīng zhì', + '牡丹亭' => ' mǔ dan tíng', + '牡丹坊' => ' mǔ dan fāng', + '切面机' => ' qiē miàn jī', + '发型师' => ' fà xíng shī', + '小器作' => ' xiǎo qì zuō', + '华龙区' => ' huà lóng qū', + '切片机' => ' qiē piàn jī', + '高丽朝' => ' gāo lí cháo', + '高丽参' => ' gāo lí shēn', + '洞子货' => ' dòng zǐ huò', + '面人儿' => ' miàn rén ér', + '先君子' => ' xiān jūn zǐ', + '犬夜叉' => ' quǎn yè chà', + '公因子' => ' gōng yīn zǐ', + '烘笼儿' => ' hōng lóng r', + '三毛猫' => ' sān máo māo', + '窝囊废' => ' wō nāng fèi', + '弦乐器' => ' xián yuè qì', + '三班倒' => ' sān bān dǎo', + '八行书' => ' bā háng shū', + '有时候' => ' yǒu shí hou', + '蛋白石' => ' dàn bái shí', + '波带片' => ' bō dài piān', + '鹿谷乡' => ' lù gǔ xiāng', + '磁感应' => ' cí gǎn yìng', + '电子书' => ' diàn zǐ shū', + '顾颉刚' => ' gù xié gāng', + '电子学' => ' diàn zǐ xué', + '校对机' => ' jiào duì jī', + '感应力' => ' gǎn yìng lì', + '感应炉' => ' gǎn yìng lú', + '漂流木' => ' piāo liú mù', + '敞开儿' => ' chǎng kāi r', + '漂流物' => ' piāo liú wù', + '省劲儿' => ' shěng jìn r', + '处理权' => ' chǔ lǐ quán', + '吃不了' => ' chī bù liǎo', + '原子价' => ' yuán zǐ jià', + '干洗店' => ' gān xǐ diàn', + '电子琴' => ' diàn zǐ qín', + '电子云' => ' diàn zǐ yún', + '工夫茶' => ' gōng fu chá', + '放得下' => ' fàng de xià', + '罗刹国' => ' luó chà guó', + '箭垛子' => ' jiàn duò zi', + '升压器' => ' shēng yà qì', + '百分号' => ' bǎi fēn háo', + '谷梁传' => ' gǔ liáng zhuàn', + '摆擂台' => ' bǎi lèi tái', + '桌面儿' => ' zhuō miàn r', + '电子眼' => ' diàn zǐ yǎn', + '新兴区' => ' xīn xīng qū', + '亨格洛' => ' hēng gé luò', + '长安区' => ' cháng ān qū', + '粘结力' => ' nián jié lì', + '经不住' => ' jīng bu zhù', + '热轧钢' => ' rè zhá gāng', + '仙方儿' => ' xiān fāng r', + '自感应' => ' zì gǎn yìng', + '石榴汁' => ' shí liu zhī', + '积累性' => ' jī lěi xìng', + '原子论' => ' yuán zǐ lùn', + '磁测量' => ' cí cè liáng', + '镇得住' => ' zhèn de zhù', + '栽跟头' => ' zāi gēn tou', + '不粘锅' => ' bù nián guō', + '尉迟恭' => ' yù chí gōng', + '票贩子' => ' piào fàn zǐ', + '漂泊者' => ' piāo bó zhě', + '磨坊主' => ' mò fáng zhǔ', + '室间隔' => ' shì jiàn gé', + '人造草' => ' rén zào cǎo', + '穿衣服' => ' chuān yī fu', + '济宁市' => ' jǐ níng shì', + '旅行家' => ' lǚ háng jia', + '出疹子' => ' chū zhěn zǐ', + '枪杆儿' => ' qiāng gǎn r', + '迎宾曲' => ' yíng bīn qǔ', + '嚼裹儿' => ' jiáo guǒ ér', + '粘膜炎' => ' nián mó yán', + '小插曲' => ' xiǎo chā qǔ', + '干扰者' => ' gān rǎo zhě', + '闹乱子' => ' nào luàn zǐ', + '讲义气' => ' jiǎng yì qi', + '不中意' => ' bù zhòng yì', + '插杠子' => ' chā gàng zi', + '相思曲' => ' xiāng sī qǔ', + '相思子' => ' xiāng sī zǐ', + '枪子儿' => ' qiāng zǐ er', + '曹不兴' => ' cáo bù xīng', + '嫡长子' => ' dí zhǎng zǐ', + '耳咽管' => ' ěr yān guǎn', + '香附子' => ' xiāng fù zǐ', + '调节剂' => ' tiáo jié jì', + '变样儿' => ' biàn yàng r', + '嫌麻烦' => ' xián má fan', + '贱骨头' => ' jiàn gú tou', + '测量器' => ' cè liáng qì', + '出大差' => ' chū dà chāi', + '上钩儿' => ' shàng gōu r', + '蒙古国' => ' měng gǔ guó', + '蒙古包' => ' měng gǔ bāo', + '丽水市' => ' lí shuǐ shì', + '调制器' => ' tiáo zhì qì', + '变奏曲' => ' biàn zòu qǔ', + '烫头发' => ' tàng tóu fa', + '蒙古人' => ' měng gǔ rén', + '曾孙女' => ' zēng sūn nǚ', + '蒙代尔' => ' mēng dài ěr', + '老家伙' => ' lǎo jiā huo', + '卖关子' => ' mài guān zǐ', + '前处理' => ' qián chǔ lǐ', + '够不着' => ' gòu bù zháo', + '船夫曲' => ' chuán fū qǔ', + '澄泥砚' => ' dèng ní yàn', + '新都桥' => ' xīn dū qiáo', + '电子狗' => ' diàn zǐ gǒu', + '系列片' => ' xì liè piān', + '罗唝曲' => ' luó gòng qǔ', + '尹潽善' => ' yǐn pǔ shàn', + '电子束' => ' diàn zǐ shù', + '摽劲儿' => ' biào jìn er', + '背黑锅' => ' bēi hēi guō', + '调皮鬼' => ' tiáo pí guǐ', + '虎跑泉' => ' hǔ páo quán', + '够得着' => ' gòu de zháo', + '低转速' => ' dī zhuàn sù', + '爵士乐' => ' jué shì yuè', + '浪漫曲' => ' làng màn qǔ', + '买东西' => ' mǎi dōng xi', + '指甲刀' => ' zhǐ jia dāo', + '标识符' => ' biāo zhì fú', + '片儿警' => ' piàn r jǐng', + '调频器' => ' tiáo pín qì', + '标识码' => ' biāo zhì mǎ', + '脑梗塞' => ' nǎo gěng sè', + '资兴市' => ' zī xīng shì', + '鸭绿江' => ' yā lù jiāng', + '贾平凹' => ' jiǎ píng wā', + '已更新' => ' yǐ gēng xīn', + '不要脸' => ' bú yào liǎn', + '解调器' => ' jiě tiáo qì', + '听不见' => ' tīng bu jiàn', + '用得着' => ' yòng de zháo', + '用不了' => ' yòng bù liǎo', + '澎湖县' => ' péng hú xiàn', + '生闷气' => ' shēng mēn qì', + '进给量' => ' jìn jǐ liàng', + '咽喉痛' => ' yān hóu tòng', + '甚高频' => ' shèn gāo pín', + '装糊涂' => ' zhuāng hú tu', + '甲壳类' => ' jiǎ qiào lèi', + '转载机' => ' zhuǎn zǎi jī', + '柏林墙' => ' bó lín qiáng', + '听得懂' => ' tīng de dǒng', + '延长器' => ' yán cháng qì', + '肺栓塞' => ' fèi shuān sè', + '知识面' => ' zhī shi miàn', + '知识性' => ' zhī shi xìng', + '不相干' => ' bù xiāng gān', + '指定值' => ' zhǐ dìng zhí', + '天晓得' => ' tiān xiǎo de', + '佳丽酿' => ' jiā lì niáng', + '黄葛树' => ' huáng gě shù', + '绿营兵' => ' lù yíng bīng', + '总干事' => ' zǒng gàn shi', + '江都市' => ' jiāng dū shì', + '东兴区' => ' dōng xīng qū', + '伊甸园' => ' yī diàn yuán', + '沂蒙山' => ' yí měng shān', + '用不着' => ' yòng bù zháo', + '果子酱' => ' guǒ zǐ jiàng', + '大藏经' => ' dà zàng jīng', + '脚趾头' => ' jiǎo zhǐ tou', + '照片儿' => ' zhào piān er', + '硬着陆' => ' yìng zhuó lù', + '二重根' => ' èr chóng gēn', + '兴教寺' => ' xīng jiào sì', + '校准器' => ' jiào zhǔn qì', + '女傧相' => ' nǚ bīn xiàng', + '当回事' => ' dàng huí shì', + '调整到' => ' tiáo zhěng dào', + '珲春市' => ' hún chūn shì', + '统称为' => ' tǒng chēng wéi', + '脚指甲' => ' jiǎo zhǐ jia', + '潭子乡' => ' tán zǐ xiāng', + '佛坪县' => ' fó píng xiàn', + '脑卒中' => ' nǎo cù zhòng', + '考试卷' => ' kǎo shì juàn', + '大黄鱼' => ' dài huáng yú', + '民乐县' => ' mín yuè xiàn', + '海参崴' => ' hǎi shēn wēi', + '使兴奋' => ' shǐ xīng fèn', + '姬松茸' => ' jī sōng róng', + '正角儿' => ' zhèng jué er', + '钻井机' => ' zuàn jǐng jī', + '槟榔屿' => ' bīng láng yǔ', + '柬埔寨' => ' jián pǔ zhài', + '老朋友' => ' lǎo péng you', + '柳毅传' => ' lǐu yì zhuàn', + '佛冈县' => ' fó gāng xiàn', + '行为学' => ' xíng wéi xué', + '繁峙县' => ' fán shì xiàn', + '算不了' => ' suàn bù liǎo', + '蒙松雨' => ' mēng sōng yǔ', + '灾难性' => ' zāi nàn xìng', + '美差事' => ' měi chāi shì', + '羊痒疫' => ' yáng yǎng yì', + '失忆症' => ' shī yì zhèng', + '钻石婚' => ' zuàn shí hūn', + '燕麦粥' => ' yān mài zhōu', + '应急灯' => ' yìng jí dēng', + '西洋参' => ' xī yáng shēn', + '还魂丹' => ' huán hún dān', + '看守所' => ' kān shǒu suǒ', + '榴霰弹' => ' liú xiàn dàn', + '虞应龙' => ' yú yìng lóng', + '蟹爪兰' => ' xiè zhuǎ lán', + '转弯子' => ' zhuàn wān zi', + '无穷尽' => ' wú qióng jìn', + '文冠果' => ' wén guàn guǒ', + '间接费' => ' jiàn jiē fèi', + '少不了' => ' shào bù liǎo', + '螺桨毂' => ' luó jiǎng gū', + '原子尘' => ' yuán zǐ chén', + '上边儿' => ' shàng bian r', + '萧子显' => ' xiāo zǐ xiǎn', + '氧原子' => ' yǎng yuán zǐ', + '军乐团' => ' jūn yuè tuán', + '张柏芝' => ' zhāng bó zhī', + '多水分' => ' duō shuǐ fèn', + '子弹箱' => ' zǐ dàn xiāng', + '负效应' => ' fù xiào yìng', + '畹町市' => ' wǎn dīng shì', + '狮子乡' => ' shī zǐ xiāng', + '钻孔机' => ' zuàn kǒng jī', + '折杨柳' => ' shé yáng liǔ', + '失身分' => ' shī shēn fèn', + '总供给' => ' zǒng gōng jǐ', + '缝针迹' => ' féng zhēn jì', + '舟曲县' => ' zhōu qǔ xiàn', + '缝衣针' => ' féng yī zhēn', + '缅甸语' => ' miǎn diàn yǔ', + '接插件' => ' jiē chā jiàn', + '校准仪' => ' jiào zhǔn yí', + '飞行家' => ' fēi háng jia', + '行李卷' => ' xíng lǐ juàn', + '分权制' => ' fèn quán zhì', + '娃娃装' => ' wá wa zhuāng', + '兴庆区' => ' xīng qìng qū', + '兴业县' => ' xīng yè xiàn', + '缝合线' => ' féng hé xiàn', + '老来少' => ' lǎo lái shào', + '兴化市' => ' xīng huà shì', + '兴和县' => ' xīng hé xiàn', + '兴安盟' => ' xīng ān méng', + '兴安县' => ' xīng ān xiàn', + '兴宁区' => ' xīng níng qū', + '兴山区' => ' xīng shān qū', + '林家翘' => ' lín jiā qiáo', + '宝生佛' => ' bǎo shēng fó', + '枕头套' => ' zhěn tou tào', + '灾难片' => ' zāi nàn piàn', + '大长今' => ' dà cháng jīn', + '桦甸市' => ' huà diàn shì', + '管不着' => ' guǎn bu zháo', + '张掖市' => ' zhāng yè shì', + '干燥瓶' => ' gān zào píng', + '反应池' => ' fǎn yìng chí', + '横爬行' => ' héng pá xíng', + '华罗庚' => ' huà luó gēng', + '华兴会' => ' huá xīng huì', + '粘着力' => ' zhān zhuó lì', + '干鲜果' => ' gān xiān guǒ', + '粘胶液' => ' nián jiāo yè', + '李昌镐' => ' lǐ chāng hào', + '双子宫' => ' shuāng zǐ gōng', + '的确良' => ' dí què liáng', + '皇太子' => ' huáng tài zǐ', + '牡丹乡' => ' mǔ dan xiāng', + '冠军杯' => ' guàn jūn bēi', + '横筋斗' => ' héng jīn dǒu', + '航行图' => ' háng xíng tú', + '李公朴' => ' lǐ gōng piáo', + '中子弹' => ' zhōng zǐ dàn', + '少年行' => ' shào nián xíng', + '朴槿惠' => ' piáo jǐn huì', + '中子数' => ' zhōng zǐ shù', + '泰兴市' => ' tài xīng shì', + '效应器' => ' xiào yìng qì', + '小家伙' => ' xiǎo jiā huo', + '放暑假' => ' fàng shǔ jià', + '韩湘子' => ' hán xiāng zǐ', + '栽种机' => ' zāi zhòng jī', + '什邡市' => ' shí fāng shì', + '小王子' => ' xiǎo wáng zǐ', + '倒春寒' => ' dǎo chūn hán', + '脚指头' => ' jiǎo zhǐ tou', + '麻将牌' => ' má jiàng pái', + '龙门刨' => ' lóng mén bào', + '当间儿' => ' dāng jiàn ér', + '量子数' => ' liàng zǐ shù', + '都庞岭' => ' dū páng lǐng', + '钌铞儿' => ' liào diào ér', + '测量值' => ' cè liáng zhí', + '重估后' => ' chóng gū hòu', + '测量学' => ' cè liáng xué', + '大行星' => ' dà háng xīng', + '重孙子' => ' chóng sūn zi', + '重孙女' => ' chóng sūn nǚ', + '拉家常' => ' lá jiā cháng', + '剪应力' => ' jiǎn yìng lì', + '逮捕证' => ' dài bǔ zhèng', + '洋漂族' => ' yáng piāo zú', + '四重奏' => ' sì chóng zòu', + '内切圆' => ' nèi qiē yuán', + '黏涎子' => ' nián xián zǐ', + '黏着力' => ' nián zhuó lì', + '黏着语' => ' nián zhuó yǔ', + '前齿龈' => ' qián chǐ yín', + '沧浪客' => ' cāng láng kè', + '藏经阁' => ' zàng jīng gé', + '长草区' => ' cháng cǎo qū', + '酶反应' => ' méi fǎn yìng', + '炸油饼' => ' zhá yóu bǐng', + '江干区' => ' jiāng gān qū', + '应变仪' => ' yìng biàn yí', + '中大夫' => ' zhōng dài fū', + '行道树' => ' háng dào shù', + '崆峒区' => ' kōng tóng qū', + '影片儿' => ' yǐng piān er', + '烘干室' => ' hōng gān shì', + '子宫颈' => ' zǐ gōng jǐng', + '给事中' => ' jǐ shì zhōng', + '夜行性' => ' yè xíng xìng', + '着陆点' => ' zhuó lù diǎn', + '对称美' => ' duì chèn měi', + '康有为' => ' kāng yǒu wéi', + '实际上' => ' shí jì shang', + '空格键' => ' kòng gé jiàn', + '乱弹琴' => ' luàn tán qín', + '中乐透' => ' zhòng lè tòu', + '宁都县' => ' níng dū xiàn', + '小胡同' => ' xiǎo hú tòng', + '烘干窑' => ' hōng gān yáo', + '脚蹬子' => ' jiǎo dēng zǐ', + '应试者' => ' yìng shì zhě', + '干燥管' => ' gān zào guǎn', + '黑钻石' => ' hēi zuàn shí', + '中微子' => ' zhòng wēi zǐ', + '套口供' => ' tào kǒu gòng', + '亚平宁' => ' yà píng nìng', + '子洲县' => ' zǐ zhōu xiàn', + '小瘪三' => ' xiǎo biē sān', + '二重奏' => ' èr chóng zòu', + '中庶子' => ' zhōng shù zǐ', + '出洋相' => ' chū yáng xiàng', + '著作权' => ' zhù zuò quán', + '中子流' => ' zhōng zǐ liú', + '相国寺' => ' xiàng guó sì', + '花朝节' => ' huā zhāo jié', + '反应慢' => ' fǎn yìng màn', + '校验位' => ' jiào yàn wèi', + '大将军' => ' dà jiàng jūn', + '天长市' => ' tiān cháng shì', + '光杆儿' => ' guāng gǎn ér', + '这程子' => ' zhè chéng zǐ', + '京片子' => ' jīng piān zi', + '放寒假' => ' fàng hán jià', + '多重性' => ' duō chóng xìng', + '赵子龙' => ' zhào zǐ lóng', + '银行学' => ' yín háng xué', + '管乐队' => ' guǎn yuè duì', + '校勘学' => ' jiào kān xué', + '纠结点' => ' jīu jiē diǎn', + '干扰源' => ' gān rǎo yuán', + '儿童片' => ' ér tóng piān', + '李重茂' => ' lǐ chóng mào', + '行家话' => ' háng jiā huà', + '粘性力' => ' nián xìng lì', + '落埋怨' => ' lào mán yuàn', + '色达县' => ' shǎi dá xiàn', + '爪尖儿' => ' zhuǎ jiān er', + '定冠词' => ' dìng guàn cí', + '种植土' => ' zhòng zhí tǔ', + '脊神经' => ' jǐ shén jīng', + '降魔杵' => ' xiáng mó chǔ', + '童子尿' => ' tóng zǐ niào', + '二人转' => ' èr rén zhuàn', + '漂流者' => ' piāo líu zhě', + '姑娘家' => ' gū niáng jiā', + '旧框框' => ' jiù kuàng kuang', + '元好问' => ' yuán hào wèn', + '血中毒' => ' xuè zhòng dú', + '缝纫机' => ' féng rèn jī', + '无将牌' => ' wú jiàng pái', + '乾安县' => ' qián ān xiàn', + '载驳船' => ' zǎi bó chuán', + '好朋友' => ' hǎo péng you', + '弦乐队' => ' xián yuè duì', + '子宫内' => ' zǐ gōng nèi', + '串门子' => ' chuàn mén zǐ', + '翻筋斗' => ' fān jīn dǒu', + '煎炸油' => ' jiān zhá yóu', + '看上去' => ' kàn shang qu', + '石头人' => ' shí tou rén', + '女强人' => ' nǚ qiǎng rén', + '量子沫' => ' liàng zǐ mò', + '蚌山区' => ' bèng shān qū', + '伽罗华' => ' jiā luó huà', + '真番郡' => ' zhēn pān jùn', + '碳原子' => ' tàn yuán zǐ', + '少奶奶' => ' shào nǎi nɑi', + '露馅儿' => ' lòu xiàn ér', + '元真子' => ' yuán zhēn zǐ', + '广安市' => ' guǎng ān shì', + '广安门' => ' guǎng ān mén', + '轧钢厂' => ' zhá gāng chǎng', + '子宫瘤' => ' zǐ gōng liú', + '刽子手' => ' guì zǐ shǒu', + '总书记' => ' zǒng shū ji', + '薄瑞光' => ' bó ruì guāng', + '九华山' => ' jiǔ huà shān', + '抗干扰' => ' kàng gān rǎo', + '搬舌头' => ' bān shé tou', + '串处理' => ' chuàn chǔ lǐ', + '露马脚' => ' lòu mǎ jiǎo', + '阿房宫' => ' ē páng gōng', + '看不中' => ' kàn bu zhōng', + '槐荫区' => ' huái yìn qū', + '炸薯条' => ' zhá shǔ tiáo', + '照片子' => ' zhào piān zi', + '蒙嘉慧' => ' měng jiā huì', + '行列式' => ' háng liè shì', + '乐清市' => ' yuè qīng shì', + '尖沙咀' => ' jiān shā zuǐ', + '一点点' => ' yì diǎn diǎn', + '小太太' => ' xiǎo tài tai', + '种植业' => ' zhòng zhí yè', + '行得通' => ' xíng de tōng', + '竹扫帚' => ' zhú sào zhou', + '枪杆子' => ' qiāng gǎn zi', + '子宫环' => ' zǐ gōng huán', + '女舍监' => ' nǔ: shè jiān', + '瞎忙活' => ' xiā máng huo', + '朝鲜族' => ' cháo xiǎn zú', + '碰钉子' => ' pèng dìng zǐ', + '磨工病' => ' mò gōng bìng', + '漂白液' => ' piǎo bái yè', + '主属性' => ' zhǔ shǔ xìng', + '睡午觉' => ' shuì wǔ jiào', + '参宿七' => ' shēn xìu qī', + '差旅费' => ' chāi lǚ fèi', + '均方差' => ' jūn fāng chā', + '王舍城' => ' wáng shè chéng', + '半长轴' => ' bàn cháng zhóu', + '朝鲜语' => ' cháo xiǎn yǔ', + '公共课' => ' gōng gòng kè', + '莲花落' => ' lián huā lào', + '跟得上' => ' gēn de shàng', + '著作郎' => ' zhù zuò láng', + '朝歌镇' => ' zhāo gē zhèn', + '增压泵' => ' zēng yà bèng', + '原子团' => ' yuán zǐ tuán', + '氢原子' => ' qīng yuán zǐ', + '称得起' => ' chēng de qǐ', + '炸薯片' => ' zhá shǔ piàn', + '子空间' => ' zǐ kōng jiān', + '供应科' => ' gōng yìng kē', + '汽缸盖' => ' qì gāng gài', + '剪切板' => ' jiǎn qiē bǎn', + '供给者' => ' gōng jǐ zhě', + '鼓囊囊' => ' gǔ nāng nɑng', + '坏分子' => ' huài fèn zǐ', + '五通神' => ' wǔ tòng shén', + '黄药子' => ' huáng yào zǐ', + '短不了' => ' duǎn bù liǎo', + '滑行道' => ' huá háng dào', + '氧乙炔' => ' yǎng yǐ quē', + '蔺相如' => ' lìn xiàng rú', + '银行卡' => ' yín háng kǎ', + '不适当' => ' bù shì dàng', + '鹿角菜' => ' lù jiǎo cài', + '泌阳县' => ' bì yáng xiàn', + '看得中' => ' kàn de zhòng', + '五行阵' => ' wǔ háng zhèn', + '咽峡炎' => ' yān xiá yán', + '受委屈' => ' shòu wěi qu', + '金铃子' => ' jīn líng zǐ', + '功夫球' => ' gōng fu qíu', + '一块肉' => ' yí kuài ròu', + '银行业' => ' yín háng yè', + '罄身儿' => ' qìng shēn r', + '好家伙' => ' hǎo jiā huo', + '供给制' => ' gōng jǐ zhì', + '氟中毒' => ' fú zhòng dú', + '科教片' => ' kē jiào piān', + '孔丛子' => ' kǒng cóng zǐ', + '粘结剂' => ' nián jié jì', + '回流泵' => ' huí liú bèng', + '藏青色' => ' zàng qīng sè', + '三只手' => ' sān zhī shǒu', + '指头' => ' zhǐ tou', + '姘头' => ' pīn tou', + '抡才' => ' lún cái', + '碑帖' => ' bēi tiè', + '累进' => ' lěi jìn', + '嘉荫' => ' jiā yìn', + '掺杂' => ' chān zá', + '精子' => ' jīng zǐ', + '论处' => ' lùn chǔ', + '抽咽' => ' chōu yè', + '应付' => ' yìng fù', + '答卷' => ' dá juàn', + '亹亹' => ' wěi wěi', + '干瘪' => ' gān biě', + '偏曲' => ' piān qǔ', + '仙子' => ' xiān zǐ', + '变子' => ' biàn zǐ', + '蝤蛑' => ' yóu móu', + '指甲' => ' zhǐ jia', + '出塞' => ' chū sài', + '哪些' => ' něi xiē', + '筋斗' => ' jīn dǒu', + '京都' => ' jīng dū', + '桑耶' => ' sāng yē', + '元子' => ' yuán zǐ', + '丧服' => ' sāng fú', + '折煞' => ' shé shà', + '齿数' => ' chǐ shǔ', + '御苑' => ' yù yuàn', + '编曲' => ' biān qǔ', + '有处' => ' yǒu chǔ', + '梵呗' => ' fàn bài', + '难胞' => ' nàn bāo', + '咽喉' => ' yān hóu', + '处士' => ' chǔ shì', + '排车' => ' pǎi chē', + '掺合' => ' chān he', + '园子' => ' yuán zǐ', + '慰藉' => ' wèi jiè', + '筛子' => ' shāi zǐ', + '排难' => ' pái nàn', + '拾芥' => ' shí jiè', + '剥脱' => ' bāo tuō', + '条几' => ' tiáo jī', + '不更' => ' bù gēng', + '应力' => ' yìng lì', + '憎恶' => ' zēng wù', + '难属' => ' nàn shǔ', + '应急' => ' yìng jí', + '粗朴' => ' cū piáo', + '手把' => ' shǒu bà', + '楦子' => ' xuàn zǐ', + '论著' => ' lùn zhù', + '原曲' => ' yuán qǔ', + '红曲' => ' hóng qǔ', + '仔肩' => ' zī jiān', + '秧子' => ' yāng zǐ', + '懂得' => ' dǒng de', + '神佛' => ' shén fó', + '咽头' => ' yān tóu', + '答讪' => ' dā shàn', + '交恶' => ' jiāo wù', + '草舍' => ' cǎo shè', + '呼应' => ' hū yìng', + '应得' => ' yīng de', + '查下' => ' zhā xià', + '卷发' => ' juǎn fà', + '答应' => ' dā yìng', + '咽峡' => ' yān xiá', + '应和' => ' yìng hè', + '缜发' => ' zhěn fà', + '干果' => ' gān guǒ', + '梗塞' => ' gěng sè', + '嗔喝' => ' chēn hè', + '罗罗' => ' luō luō', + '难舍' => ' nán shè', + '榛子' => ' zhēn zǐ', + '嗜好' => ' shì hào', + '拐子' => ' guǎi zǐ', + '营子' => ' yíng zǐ', + '人为' => ' rén wéi', + '抹脸' => ' mā liǎn', + '绝倒' => ' jué dǎo', + '干爹' => ' gān diē', + '缨子' => ' yīng zǐ', + '查勤' => ' zhā qín', + '产子' => ' chǎn zǐ', + '牤子' => ' māng zǐ', + '攮子' => ' nǎng zǐ', + '缏子' => ' biàn zǐ', + '干杯' => ' gān bēi', + '查数' => ' zhā shù', + '才尽' => ' cái jìn', + '策应' => ' cè yìng', + '插接' => ' chā jiē', + '难友' => ' nàn yǒu', + '福兴' => ' fú xīng', + '披卷' => ' pī juàn', + '查察' => ' zhā chá', + '粘附' => ' nián fù', + '攒盒' => ' cuán hé', + '纤夫' => ' qiàn fū', + '团子' => ' tuán zǐ', + '采血' => ' cǎi xiě', + '应物' => ' yìng wù', + '咽炎' => ' yān yán', + '拌和' => ' bàn huò', + '论难' => ' lùn nàn', + '玉琢' => ' yù zhuó', + '缝合' => ' féng hé', + '折头' => ' zhé tou', + '繁峙' => ' fán shì', + '壅塞' => ' yōng sè', + '棒喝' => ' bàng hè', + '边子' => ' biān zǐ', + '糊弄' => ' hù nòng', + '休假' => ' xiū jià', + '粘液' => ' nián yè', + '干尸' => ' gān shī', + '蒙族' => ' měng zú', + '从子' => ' cóng zǐ', + '粘度' => ' nián dù', + '嗳酸' => ' ǎi suān', + '一卷' => ' yī juàn', + '一通' => ' yī tòng', + '缝补' => ' féng bǔ', + '龙脊' => ' lóng jǐ', + '不省' => ' bù xǐng', + '一天' => ' yì tiān', + '宁子' => ' níng zǐ', + '门斗' => ' mén dǒu', + '吓倒' => ' xià dǎo', + '舍下' => ' shè xià', + '参错' => ' cēn cuò', + '不甚' => ' bù shèn', + '拚贴' => ' pīn tiē', + '闷雷' => ' mēn léi', + '拗劲' => ' niù jìn', + '漂儿' => ' piāo ér', + '闭卷' => ' bì juàn', + '干草' => ' gān cǎo', + '绵薄' => ' mián bó', + '拖累' => ' tuō lěi', + '遗少' => ' yí shào', + '粘土' => ' nián tǔ', + '捻子' => ' niǎn zǐ', + '噱头' => ' xué tou', + '一了' => ' yī liǎo', + '砚台' => ' yàn tāi', + '灵子' => ' líng zǐ', + '灶头' => ' zào tou', + '桔槔' => ' jié gāo', + '拗陷' => ' ào xiàn', + '粘糊' => ' nián hū', + '杠子' => ' gàng zi', + '别别' => ' biè biè', + '应举' => ' yìng jǔ', + '折本' => ' shé běn', + '杆菌' => ' gǎn jūn', + '瀑流' => ' bào liú', + '严查' => ' yán zhā', + '宝刹' => ' bǎo chà', + '杠夫' => ' gàng fū', + '吴兴' => ' wú xīng', + '干贝' => ' gān bèi', + '粘合' => ' nián hé', + '粘米' => ' nián mǐ', + '藏历' => ' zàng lì', + '端的' => ' duān dì', + '篇子' => ' piān zǐ', + '所为' => ' suǒ wéi', + '骠骑' => ' piào qí', + '藏医' => ' zàng yī', + '空儿' => ' kòng ér', + '恫吓' => ' dòng hè', + '卜算' => ' bǔ suàn', + '灶火' => ' zào huō', + '嚼蜡' => ' jiáo là', + '石作' => ' shí zuō', + '以还' => ' yǐ huán', + '仿似' => ' fǎng sì', + '石头' => ' shí tou', + '藏戏' => ' zàng xì', + '大卷' => ' dà juàn', + '半宿' => ' bàn xiǔ', + '鱼漂' => ' yú piāo', + '臧否' => ' zāng pǐ', + '扳倒' => ' bān dǎo', + '碇泊' => ' dìng bó', + '嚼子' => ' jiáo zǐ', + '查查' => ' zhā zhā', + '刺痒' => ' cì yáng', + '喽喽' => ' lou lou', + '存查' => ' cún zhā', + '摧折' => ' cuī shé', + '五更' => ' wǔ gēng', + '案卷' => ' àn juàn', + '令子' => ' lìng zǐ', + '拶指' => ' zǎn zhǐ', + '扒手' => ' pá shǒu', + '梵刹' => ' fàn chà', + '应募' => ' yìng mù', + '呢绒' => ' ní róng', + '恶相' => ' è xiàng', + '愚氓' => ' yú méng', + '晕高' => ' yùn gāo', + '伴乐' => ' bàn yuè', + '灾煞' => ' zāi shà', + '流尽' => ' liú jìn', + '牛舍' => ' niú shè', + '一着' => ' yī zhāo', + '绷子' => ' bēng zǐ', + '笔供' => ' bǐ gòng', + '管子' => ' guǎn zǐ', + '丧仪' => ' sāng yí', + '排叉' => ' pái chà', + '扎囊' => ' zā náng', + '干旱' => ' gān hàn', + '哽咽' => ' gěng yè', + '攒集' => ' cuán jí', + '折耗' => ' shé hào', + '啴啴' => ' tān tān', + '累累' => ' lěi lěi', + '漏尽' => ' lòu jìn', + '悲咽' => ' bēi yān', + '算子' => ' suàn zǐ', + '拢子' => ' lǒng zǐ', + '鱼卷' => ' yú juàn', + '龙子' => ' lóng zǐ', + '攒聚' => ' cuán jù', + '干嚎' => ' gān háo', + '云为' => ' yún wéi', + '磨削' => ' mó xiāo', + '郢都' => ' yǐng dū', + '哪边' => ' nǎ bian', + '刺参' => ' cì shēn', + '不调' => ' bù tiáo', + '镚子' => ' bèng zǐ', + '绫子' => ' líng zǐ', + '猛子' => ' měng zǐ', + '拜倒' => ' bài dǎo', + '硙硙' => ' wèi wèi', + '干燥' => ' gān zào', + '有分' => ' yǒu fèn', + '粘膜' => ' nián mó', + '吸着' => ' xī zhuó', + '磅礴' => ' páng bó', + '粘聚' => ' nián jù', + '能子' => ' néng zǐ', + '折箩' => ' zhē luó', + '一觉' => ' yī jiào', + '呵欠' => ' hē qiàn', + '被难' => ' bèi nàn', + '半折' => ' bàn shé', + '乐池' => ' yuè chí', + '才分' => ' cái fèn', + '罗刹' => ' luó chà', + '仆从' => ' pú cóng', + '哗然' => ' huá rán', + '磨坊' => ' mò fáng', + '干货' => ' gān huò', + '干透' => ' gān tòu', + '查报' => ' zhā bào', + '蒙医' => ' měng yī', + '碑拓' => ' bēi tuò', + '乐感' => ' yuè gǎn', + '干酪' => ' gān lào', + '已甚' => ' yǐ shèn', + '栽倒' => ' zāi dǎo', + '拖斗' => ' tuō dǒu', + '乾安' => ' qián ān', + '碾子' => ' niǎn zǐ', + '些子' => ' xiē zǐ', + '干脆' => ' gān cuì', + '主仆' => ' zhǔ pú', + '干枯' => ' gān kū', + '荀子' => ' xún zǐ', + '丸子' => ' wán zǐ', + '芋头' => ' yù tou', + '碟子' => ' dié zǐ', + '丹佛' => ' dān fó', + '茶几' => ' chá jī', + '颉利' => ' xié lì', + '茬子' => ' chá zǐ', + '茅厕' => ' máo si', + '芍陂' => ' què pí', + '干涸' => ' gān hé', + '乐谱' => ' yuè pǔ', + '茄子' => ' qié zi', + '乐府' => ' yuè fǔ', + '簪子' => ' zān zǐ', + '矸子' => ' gān zǐ', + '倒塌' => ' dǎo tā', + '花蛤' => ' huā gé', + '怎得' => ' zěn de', + '贼子' => ' zéi zǐ', + '心曲' => ' xīn qǔ', + '花都' => ' huā dū', + '干洗' => ' gān xǐ', + '蟹子' => ' xiè zǐ', + '倒地' => ' dǎo dì', + '看似' => ' kàn sì', + '踅子' => ' xué zǐ', + '不住' => ' bú zhù', + '茓子' => ' xué zǐ', + '雪子' => ' xuě zǐ', + '来得' => ' lái de', + '腕子' => ' wàn zǐ', + '薄弱' => ' bó ruò', + '着哩' => ' zhe lǐ', + '落得' => ' luò de', + '茄科' => ' qié kē', + '乙炔' => ' yǐ quē', + '乜嘢' => ' niè yě', + '干菜' => ' gān cài', + '看押' => ' kān yā', + '看护' => ' kān hù', + '倒戈' => ' dǎo gē', + '倒伏' => ' dǎo fú', + '花呢' => ' huā ní', + '砟子' => ' zhǎ zǐ', + '倒序' => ' dǎo xù', + '渣子' => ' zhā zǐ', + '破处' => ' pò chǔ', + '眸子' => ' móu zǐ', + '乐曲' => ' yuè qǔ', + '心子' => ' xīn zǐ', + '石勒' => ' shí lè', + '有得' => ' yǒu de', + '发卡' => ' fà qiǎ', + '菹醢' => ' zū hǎi', + '科斗' => ' kē dǒu', + '白发' => ' bái fà', + '白鹄' => ' bái hú', + '菲姬' => ' fěi jī', + '的士' => ' dí shì', + '的确' => ' dí què', + '秦都' => ' qín dū', + '私处' => ' sī chǔ', + '休得' => ' xiū de', + '寓舍' => ' yù shè', + '落子' => ' lào zǐ', + '熨帖' => ' yù tiē', + '羞恶' => ' xiū wù', + '发帖' => ' fā tiě', + '吁求' => ' yù qiú', + '萎靡' => ' wěi mǐ', + '稚子' => ' zhì zǐ', + '与人' => ' yú rén', + '发难' => ' fā nàn', + '白佛' => ' bái fó', + '于思' => ' yú sāi', + '落下' => ' là xià', + '白子' => ' bái zǐ', + '与闻' => ' yù wén', + '萎叶' => ' wěi yè', + '信子' => ' xìn zǐ', + '崽子' => ' zǎi zǐ', + '芯子' => ' xìn zǐ', + '乐器' => ' yuè qì', + '乐律' => ' yuè lǜ', + '干儿' => ' gān ér', + '仔仔' => ' zǐ zǎi', + '范蠡' => ' fàn lǐ', + '云子' => ' yún zǐ', + '杂处' => ' zá chǔ', + '扎紧' => ' zā jǐn', + '苦难' => ' kǔ nàn', + '苦处' => ' kǔ chǔ', + '载负' => ' zǎi fù', + '丫头' => ' yā tou', + '乳晕' => ' rǔ yùn', + '砣子' => ' tuó zǐ', + '砌末' => ' qiè mò', + '花子' => ' huā zǐ', + '瞽阇' => ' gǔ shé', + '砂子' => ' shā zǐ', + '新曲' => ' xīn qǔ', + '草耙' => ' cǎo pá', + '倒把' => ' dǎo bǎ', + '极为' => ' jí wéi', + '丫杈' => ' yā chà', + '由得' => ' yóu de', + '历数' => ' lì shǔ', + '乐迷' => ' yuè mí', + '疏勒' => ' shū lè', + '落泊' => ' luò bó', + '直得' => ' zhí de', + '痱子' => ' fèi zǐ', + '积累' => ' jī lěi', + '油子' => ' yóu zǐ', + '许处' => ' xǔ chǔ', + '釉子' => ' yòu zǐ', + '番禺' => ' pān yú', + '只此' => ' zhī cǐ', + '桠杈' => ' yā chà', + '不菲' => ' bù fěi', + '干衣' => ' gān yī', + '与会' => ' yù huì', + '不要' => ' bú yào', + '余处' => ' yú chǔ', + '橱子' => ' chú zǐ', + '逾分' => ' yú fèn', + '楔子' => ' xiē zǐ', + '果子' => ' guǒ zǐ', + '枚卜' => ' méi bǔ', + '例假' => ' lì jià', + '独处' => ' dú chǔ', + '脊背' => ' jǐ bèi', + '瘫子' => ' tān zǐ', + '折翼' => ' shé yì', + '压载' => ' yā zǎi', + '瓜子' => ' guā zǐ', + '卧倒' => ' wò dǎo', + '琢磨' => ' zuó mo', + '不对' => ' bú duì', + '枯干' => ' kū gān', + '倒闭' => ' dǎo bì', + '瓤儿' => ' ráng r', + '窥伺' => ' kuī sì', + '窑子' => ' yáo zǐ', + '枣子' => ' zǎo zǐ', + '幽咽' => ' yōu yè', + '止咳' => ' zhǐ ké', + '臊子' => ' sào zǐ', + '倒爷' => ' dǎo yé', + '舀子' => ' yǎo zǐ', + '质的' => ' zhì dì', + '征辟' => ' zhǐ bì', + '瘤子' => ' liú zǐ', + '不遂' => ' bù suí', + '疟子' => ' yào zǐ', + '瘸子' => ' qué zǐ', + '瘊子' => ' hóu zǐ', + '癖好' => ' pǐ hào', + '哲子' => ' zhé zǐ', + '稻子' => ' dào zǐ', + '脊髓' => ' jǐ suǐ', + '压蔓' => ' yā wàn', + '牙龈' => ' yá yín', + '支子' => ' zhī zǐ', + '主薄' => ' zhǔ bù', + '爆肚' => ' bào dǔ', + '笔杆' => ' bǐ gǎn', + '不到' => ' bú dào', + '笆斗' => ' bā dǒu', + '学佛' => ' xué fó', + '狍子' => ' páo zǐ', + '过得' => ' guò de', + '荤粥' => ' xūn yù', + '武侯' => ' wǔ hòu', + '犹子' => ' yóu zǐ', + '只字' => ' zhī zì', + '无干' => ' wú gān', + '之子' => ' zhī zǐ', + '葛优' => ' gě yōu', + '竿子' => ' gān zǐ', + '脱发' => ' tuō fà', + '腰子' => ' yāo zǐ', + '牢子' => ' láo zǐ', + '使得' => ' shǐ de', + '下子' => ' xià zǐ', + '答白' => ' dā bái', + '夏子' => ' xià zǐ', + '历尽' => ' lì jìn', + '侉子' => ' kuǎ zǐ', + '殷都' => ' yīn dū', + '蕃庑' => ' fán wú', + '脊肋' => ' jǐ lèi', + '煞气' => ' shà qì', + '无处' => ' wú chǔ', + '蔫儿' => ' niān r', + '梅子' => ' méi zǐ', + '下得' => ' xià de', + '栀子' => ' zhī zǐ', + '下都' => ' xià dū', + '柏悦' => ' bó yuè', + '热帖' => ' rè tiě', + '押头' => ' yā tou', + '死难' => ' sǐ nàn', + '脊柱' => ' jǐ zhù', + '西乐' => ' xī yuè', + '为期' => ' wéi qī', + '乌什' => ' wū shí', + '值得' => ' zhí de', + '薄厚' => ' bó hòu', + '作曲' => ' zuò qǔ', + '作死' => ' zuō sǐ', + '脊索' => ' jǐ suǒ', + '无为' => ' wú wéi', + '柏林' => ' bó lín', + '无尽' => ' wú jìn', + '芜累' => ' wú lěi', + '槟子' => ' bīn zǐ', + '尽力' => ' jìn lì', + '任人' => ' rèn rén', + '胳臂' => ' gē bei', + '炸鸡' => ' zhá jī', + '人儿' => ' rén ér', + '鹞子' => ' yào zǐ', + '系留' => ' jì liú', + '翅子' => ' chì zǐ', + '一干' => ' yī gān', + '没落' => ' mò luò', + '子书' => ' zǐ shū', + '一般' => ' yì bān', + '薄酒' => ' bó jiǔ', + '处罚' => ' chǔ fá', + '佛陀' => ' fó tuó', + '佛门' => ' fó mén', + '栽子' => ' zāi zǐ', + '处死' => ' chǔ sǐ', + '美的' => ' měi dí', + '比才' => ' bì cái', + '假日' => ' jià rì', + '粪耙' => ' fèn pá', + '佛龛' => ' fó kān', + '混子' => ' hùn zǐ', + '为伍' => ' wéi wǔ', + '薄海' => ' bó hǎi', + '炸鱼' => ' zhá yú', + '美发' => ' měi fà', + '罗勒' => ' luó lè', + '柞栎' => ' zuò lì', + '柔佛' => ' róu fó', + '分子' => ' fèn zǐ', + '结发' => ' jié fà', + '虾子' => ' xiā zǐ', + '沤肥' => ' òu féi', + '何干' => ' hé gān', + '柚木' => ' yóu mù', + '浸没' => ' jìn mò', + '荫庇' => ' yìn bì', + '海子' => ' hǎi zǐ', + '栅子' => ' zhà zǐ', + '子惠' => ' zǐ huì', + '毛肚' => ' máo dǔ', + '自好' => ' zì hào', + '组分' => ' zǔ fèn', + '什器' => ' shí qì', + '自处' => ' zì chǔ', + '一舍' => ' yī shè', + '木杆' => ' mù gǎn', + '问卜' => ' wèn bǔ', + '滚子' => ' gǔn zǐ', + '子月' => ' zǐ yuè', + '假期' => ' jià qī', + '淹没' => ' yān mò', + '饮子' => ' yǐn zǐ', + '围子' => ' wéi zǐ', + '老姥' => ' lǎo mǔ', + '似雪' => ' sì xuě', + '人子' => ' rén zǐ', + '罹难' => ' lí nàn', + '一匙' => ' yī chí', + '缉查' => ' jī zhā', + '作揖' => ' zuō yī', + '一带' => ' yí dài', + '一宿' => ' yī xiǔ', + '伺候' => ' cì hou', + '约塔' => ' yāo tǎ', + '泡子' => ' pāo zǐ', + '脂麻' => ' zhī ma', + '胞子' => ' bāo zǐ', + '子男' => ' zǐ nán', + '稠糊' => ' chóu hū', + '应答' => ' yìng dá', + '垸子' => ' yuàn zǐ', + '背着' => ' bēi zhe', + '出倒' => ' chū dǎo', + '乱子' => ' luàn zǐ', + '卖解' => ' mài xiè', + '偏得' => ' piān de', + '应敌' => ' yìng dí', + '绷瓷' => ' bèng cí', + '秦桧' => ' qín huì', + '处理' => ' chǔ lǐ', + '帷子' => ' wéi zǐ', + '处于' => ' chǔ yú', + '假子' => ' jiǎ zǐ', + '耗子' => ' hào zǐ', + '没药' => ' mò yào', + '泊车' => ' bó chē', + '绿林' => ' lù lín', + '微子' => ' wēi zǐ', + '处女' => ' chǔ nǚ', + '泊位' => ' bó wèi', + '毛厕' => ' máo si', + '河叉' => ' hé chà', + '泡吧' => ' pào bā', + '续假' => ' xù jià', + '未卜' => ' wèi bǔ', + '五斗' => ' wǔ dǒu', + '苇子' => ' wěi zǐ', + '一化' => ' yī huā', + '蝎子' => ' xiē zǐ', + '佛家' => ' fó jiā', + '圩子' => ' wéi zǐ', + '佛学' => ' fó xué', + '絮叨' => ' xù dáo', + '沙拉' => ' shā là', + '臆度' => ' yì duó', + '催吐' => ' cuī tù', + '藉以' => ' jiè yǐ', + '染发' => ' rǎn fà', + '屋舍' => ' wū shè', + '尽意' => ' jìn yì', + '檐子' => ' yán zǐ', + '菌子' => ' jùn zi', + '磨碎' => ' mò suì', + '舍弟' => ' shè dì', + '束发' => ' shù fà', + '尽速' => ' jìn sù', + '薄待' => ' bó dài', + '梭子' => ' suō zǐ', + '佛号' => ' fó hào', + '雁子' => ' yàn zǐ', + '子金' => ' zǐ jīn', + '烟子' => ' yān zǐ', + '蚂蚱' => ' mà zhà', + '磨难' => ' mó nàn', + '一到' => ' yí dào', + '累计' => ' lěi jì', + '活似' => ' huó sì', + '兰若' => ' lán rě', + '活佛' => ' huó fó', + '眼子' => ' yǎn zǐ', + '子衿' => ' zǐ jīn', + '肋骨' => ' lèi gǔ', + '一撮' => ' yī zuǒ', + '佚失' => ' yì shī', + '议处' => ' yì chǔ', + '舍利' => ' shè lì', + '倒替' => ' dǎo tì', + '蜗杆' => ' wō gǎn', + '楼子' => ' lóu zǐ', + '倒毙' => ' dǎo bì', + '磨烦' => ' mò fán', + '李适' => ' lǐ kuò', + '信佛' => ' xìn fó', + '模板' => ' mú bǎn', + '直发' => ' zhí fà', + '磨盘' => ' mò pán', + '般乐' => ' pán lè', + '乐户' => ' yuè hù', + '干涩' => ' gān sè', + '磨叨' => ' mò dāo', + '乐舞' => ' yuè wǔ', + '盘曲' => ' pán qǔ', + '干渴' => ' gān kě', + '乐歌' => ' yuè gē', + '华发' => ' huá fà', + '莞尔' => ' wǎn ěr', + '俟候' => ' sì hòu', + '祝发' => ' zhù fà', + '东阿' => ' dōng ē', + '杯葛' => ' bēi gě', + '李悝' => ' lǐ kuī', + '旧都' => ' jiù dū', + '尽责' => ' jìn zé', + '文曲' => ' wén qǔ', + '介子' => ' jiè zǐ', + '查缉' => ' zhā jī', + '蛙鞋' => ' wā xié', + '肉脯' => ' ròu fǔ', + '湮没' => ' yān mò', + '沦没' => ' lún mò', + '结扎' => ' jié zā', + '号子' => ' hào zǐ', + '什叶' => ' shí yè', + '子畜' => ' zǐ chù', + '淡泊' => ' dàn bó', + '仆人' => ' pú rén', + '蛤蚧' => ' gé jiè', + '淡薄' => ' dàn bó', + '结壳' => ' jiē ké', + '饮马' => ' yìn mǎ', + '结子' => ' jié zǐ', + '子道' => ' zǐ dào', + '木头' => ' mù tou', + '查核' => ' zhā hé', + '蚶子' => ' hān zǐ', + '子都' => ' zǐ dōu', + '何处' => ' hé chǔ', + '亏得' => ' kuī de', + '虺蜥' => ' huǐ xī', + '译著' => ' yì zhù', + '佛书' => ' fó shū', + '兀鹫' => ' wū jiù', + '纰缪' => ' pī miù', + '淫靡' => ' yín mǐ', + '毫发' => ' háo fà', + '企划' => ' qǐ huá', + '子侄' => ' zǐ zhí', + '活泛' => ' huó fá', + '累积' => ' lěi jī', + '一撇' => ' yī piě', + '以为' => ' yǐ wéi', + '渡假' => ' dù jià', + '毛发' => ' máo fà', + '背逆' => ' bēi nì', + '假发' => ' jiǎ fà', + '背负' => ' bēi fù', + '结巴' => ' jiē bā', + '摇把' => ' yáo bà', + '泰勒' => ' tài lè', + '背脊' => ' bèi jǐ', + '子口' => ' zǐ kǒu', + '闻得' => ' wén de', + '济南' => ' jǐ nán', + '澹泊' => ' dàn bó', + '测度' => ' cè duó', + '给事' => ' jǐ shì', + '纳什' => ' nà shí', + '纽子' => ' niǔ zǐ', + '绦子' => ' tāo zǐ', + '单于' => ' chán yú', + '绢子' => ' juàn zǐ', + '绵子' => ' mián zǐ', + '弹回' => ' tán huí', + '弹斥' => ' tán chì', + '垫子' => ' diàn zǐ', + '坠子' => ' zhuì zǐ', + '弹指' => ' tán zhǐ', + '罩子' => ' zhào zǐ', + '弹射' => ' tán shè', + '斗车' => ' dǒu chē', + '弹奏' => ' tán zòu', + '折到' => ' shé dào', + '斗酒' => ' dǒu jiǔ', + '折过' => ' zhē guò', + '会稽' => ' kuài jī', + '洞子' => ' dòng zǐ', + '发丧' => ' fā sāng', + '白术' => ' bái zhú', + '弹琴' => ' tán qín', + '吊子' => ' diào zǐ', + '磈磊' => ' kuǐ lěi', + '塞外' => ' sài wài', + '檃栝' => ' yǐn kuò', + '窥度' => ' kuī duó', + '定都' => ' dìng dū', + '招子' => ' zhāo zǐ', + '番茄' => ' fān qié', + '档子' => ' dàng zǐ', + '飞掠' => ' fēi lüě', + '缝衣' => ' féng yī', + '封子' => ' fēng zǐ', + '蜂子' => ' fēng zǐ', + '市担' => ' shì dàn', + '只眼' => ' zhī yǎn', + '大兴' => ' dà xīng', + '分出' => ' fèn chū', + '干支' => ' gān zhī', + '干扰' => ' gān rǎo', + '干挠' => ' gān náo', + '球差' => ' qíu chā', + '不兴' => ' bù xīng', + '吠舍' => ' fèi shè', + '九难' => ' jiǔ nàn', + '非为' => ' fēi wéi', + '只在' => ' zhī zài', + '干休' => ' gān xiū', + '帮子' => ' bāng zǐ', + '直指' => ' zhí zhǐ', + '致知' => ' zhì zhī', + '王子' => ' wáng zǐ', + '班什' => ' bān shí', + '弥缝' => ' mí féng', + '弹球' => ' tán qíu', + '弹纠' => ' tán jīu', + '犂靬' => ' lí jiān', + '振子' => ' zhèn zǐ', + '折实' => ' shé shí', + '折损' => ' shé sǔn', + '瘪三' => ' biē sān', + '折折' => ' shé shé', + '丙子' => ' bǐng zǐ', + '靠头' => ' kào tou', + '真似' => ' zhēn sì', + '瘦子' => ' shòu zǐ', + '贞子' => ' zhēn zǐ', + '真子' => ' zhēn zǐ', + '砧子' => ' zhēn zǐ', + '疹子' => ' zhěn zǐ', + '可曾' => ' kě céng', + '课卷' => ' kè juàn', + '一哄' => ' yí hòng', + '横死' => ' hèng sǐ', + '罗嗦' => ' luō suo', + '削皮' => ' xiāo pí', + '划过' => ' huá guò', + '菸斗' => ' yān dǒu', + '划痕' => ' huá hén', + '萎缩' => ' wěi suō', + '划切' => ' huá qiè', + '斗室' => ' dǒu shì', + '都统' => ' dū tǒng', + '定子' => ' dìng zǐ', + '断喝' => ' duàn hè', + '顶子' => ' dǐng zǐ', + '款曲' => ' kuǎn qǔ', + '丁子' => ' dīng zǐ', + '锭子' => ' dìng zǐ', + '弹花' => ' tán huā', + '略为' => ' lüè wéi', + '坑子' => ' kēng zǐ', + '别扭' => ' biè niǔ', + '当机' => ' dàng jī', + '断发' => ' duàn fà', + '锻模' => ' duàn mú', + '弹出' => ' tán chū', + '外头' => ' wài tou', + '当夜' => ' dàng yè', + '当铺' => ' dàng pù', + '看门' => ' kān mén', + '欺哄' => ' qī hǒng', + '剀切' => ' kǎi qiē', + '不着' => ' bù zháo', + '建都' => ' jiàn dū', + '多难' => ' duō nàn', + '枝杈' => ' zhī chà', + '不见' => ' bú jiàn', + '犁靬' => ' lí jiān', + '净得' => ' jìng de', + '倒灶' => ' dǎo zào', + '主角' => ' zhǔ jué', + '得兼' => ' de jiān', + '坊子' => ' fāng zǐ', + '眄睨' => ' miàn nì', + '得令' => ' de lìng', + '棱子' => ' léng zǐ', + '均匀' => ' jūn yún', + '冷子' => ' lěng zǐ', + '之至' => ' zhī zhì', + '占课' => ' zhān kè', + '得神' => ' de shén', + '得算' => ' de suàn', + '圆子' => ' yuán zǐ', + '擂主' => ' lèi zhǔ', + '楞子' => ' léng zǐ', + '必应' => ' bì yìng', + '择席' => ' zhái xí', + '立卷' => ' lì juàn', + '刀切' => ' dāo qiē', + '彻查' => ' chè zhā', + '曾思' => ' zēng sī', + '德兴' => ' dé xīng', + '倒社' => ' dǎo shè', + '乐师' => ' yuè shī', + '看家' => ' kān jiā', + '倒回' => ' dǎo huí', + '倒着' => ' dǎo zhe', + '则甚' => ' zé shèn', + '曾父' => ' zēng fù', + '倒翻' => ' dǎo fān', + '倒飞' => ' dǎo fēi', + '脸子' => ' liǎn zǐ', + '倒还' => ' dǎo hái', + '乐坛' => ' yuè tán', + '倒好' => ' dǎo hǎo', + '当户' => ' dàng hù', + '瘅疟' => ' dàn nüè', + '了悟' => ' liǎo wù', + '待查' => ' dài zhā', + '累月' => ' lěi yuè', + '了如' => ' liǎo rú', + '干哕' => ' gān yuě', + '当得' => ' dāng de', + '四更' => ' sì gēng', + '待会' => ' dāi huì', + '代为' => ' dài wéi', + '丹墀' => ' dan chi', + '单处' => ' dān chǔ', + '恐吓' => ' kǒng hè', + '槵子' => ' huàn zǐ', + '燎祭' => ' liào jì', + '看头' => ' kàn tou', + '眼晕' => ' yǎn yùn', + '狗血' => ' gǒu xiě', + '庚子' => ' gēng zǐ', + '留难' => ' liú nàn', + '厦门' => ' xià mén', + '款子' => ' kuǎn zǐ', + '不当' => ' bù dàng', + '甚么' => ' shèn me', + '申曲' => ' shēn qǔ', + '著录' => ' zhù lù', + '由头' => ' yóu tou', + '发蒙' => ' fā mēng', + '卷叶' => ' juàn yè', + '发兴' => ' fā xīng', + '军乐' => ' jūn yuè', + '发还' => ' fā huán', + '只道' => ' zhī dào', + '至为' => ' zhì wéi', + '干涉' => ' gān shè', + '究诘' => ' jiū jié', + '分划' => ' fēn huá', + '猵狙' => ' piàn jū', + '分值' => ' fèn zhí', + '猜度' => ' cāi duó', + '锋镝' => ' fēng dí', + '分处' => ' fēn chǔ', + '隽秀' => ' jùn xiù', + '几谏' => ' jī jiàn', + '挓挲' => ' zhā shā', + '甚而' => ' shèn ér', + '地壳' => ' dì qiào', + '的当' => ' dí dàng', + '眯缝' => ' mī féng', + '轧车' => ' zhá chē', + '佛灯' => ' fó dēng', + '彷似' => ' fǎng sì', + '困处' => ' kùn chǔ', + '甚钜' => ' shèn jù', + '翻查' => ' fān zhā', + '翻斗' => ' fān dǒu', + '卷第' => ' juàn dì', + '直切' => ' zhí qiē', + '几丁' => ' jī dīng', + '卷末' => ' juàn mò', + '卷次' => ' juàn cì', + '肢势' => ' zhī shì', + '甚巨' => ' shèn jù', + '居丧' => ' jū sāng', + '瓦隆' => ' wǎ lōng', + '枋子' => ' fāng zǐ', + '大宛' => ' dà yuān', + '智识' => ' zhì shí', + '璧还' => ' bì huán', + '剿袭' => ' chāo xí', + '萎蕤' => ' wěi ruí', + '倒错' => ' dǎo cuò', + '倒反' => ' dǎo fǎn', + '倒休' => ' dǎo xiū', + '行都' => ' xíng dū', + '芥蓝' => ' gài lán', + '幸得' => ' xìng de', + '山曲' => ' shān qǔ', + '阿城' => ' a chéng', + '芟荑' => ' shān yí', + '行卜' => ' xíng bǔ', + '兴波' => ' xīng bō', + '衫子' => ' shān zǐ', + '苗子' => ' miáo zǐ', + '苫布' => ' shàn bù', + '若干' => ' ruò gān', + '关子' => ' guān zǐ', + '少艾' => ' shào ài', + '半载' => ' bàn zǎi', + '苦参' => ' kǔ shēn', + '阑干' => ' lán gān', + '兴德' => ' xīng dé', + '倒下' => ' dǎo xià', + '博兴' => ' bó xīng', + '隔行' => ' gé háng', + '兴发' => ' xīng fā', + '兴福' => ' xīng fú', + '隆子' => ' lóng zǐ', + '迁都' => ' qiān dū', + '丝杠' => ' sī gàng', + '还击' => ' huán jī', + '寺观' => ' sì guàn', + '四行' => ' sì háng', + '还席' => ' huán xí', + '着意' => ' zhuó yì', + '还俗' => ' huán sú', + '邀约' => ' yāo yuē', + '倒台' => ' dǎo tái', + '倒茬' => ' dǎo chá', + '四通' => ' sì tòng', + '杏脯' => ' xìng fǔ', + '还礼' => ' huán lǐ', + '著述' => ' zhù shù', + '铺面' => ' pū miàn', + '倒数' => ' dào shǔ', + '兴革' => ' xīng gé', + '杉篙' => ' shā gāo', + '杀掠' => ' shā lüě', + '芥兰' => ' gài lán', + '兴复' => ' xīng fù', + '煞有' => ' shà yǒu', + '唼喋' => ' shà zhá', + '散尽' => ' sàn jìn', + '阳曲' => ' yáng qǔ', + '死当' => ' sǐ dàng', + '铁杆' => ' tiě gǎn', + '甚于' => ' shèn yú', + '新干' => ' xīn gān', + '神子' => ' shén zǐ', + '勒庞' => ' lè páng', + '方子' => ' fāng zǐ', + '杏子' => ' xìng zǐ', + '茅舍' => ' máo shè', + '旋子' => ' xuán zǐ', + '茶匙' => ' chá chí', + '勒令' => ' lè lìng', + '勃兴' => ' bó xīng', + '斤斗' => ' jīn dǒu', + '勘查' => ' kān zhā', + '旦角' => ' dàn jué', + '铲子' => ' chǎn zǐ', + '链子' => ' liàn zǐ', + '旋木' => ' xuàn mù', + '镇咳' => ' zhèn ké', + '劲旅' => ' jìng lǚ', + '倒败' => ' dǎo bài', + '劲敌' => ' jìng dí', + '锁钥' => ' suǒ yuè', + '锁匙' => ' suǒ chí', + '神怡' => ' shēn yí', + '间隔' => ' jiàn gé', + '挼搓' => ' ruó cuō', + '三倒' => ' sān dǎo', + '散碎' => ' sǎn suì', + '若为' => ' ruò wéi', + '散粉' => ' sǎn fěn', + '散职' => ' sǎn zhí', + '舌头' => ' shé tou', + '塞北' => ' sài běi', + '附着' => ' fù zhuó', + '占卜' => ' zhān bǔ', + '散诞' => ' sǎn dàn', + '舍友' => ' shè yǒu', + '舟曲' => ' zhōu qǔ', + '阏氏' => ' yān zhī', + '形似' => ' xíng sì', + '般游' => ' pán yóu', + '散人' => ' sǎn rén', + '三舍' => ' sān shè', + '色子' => ' shǎi zǐ', + '卜宅' => ' bǔ zhái', + '仓卒' => ' cāng cù', + '卜占' => ' bǔ zhān', + '散话' => ' sǎn huà', + '兴替' => ' xīng tì', + '铺首' => ' pū shǒu', + '刨齿' => ' bào chǐ', + '刨刀' => ' bào dāo', + '晕倒' => ' yūn dǎo', + '倒楣' => ' dǎo méi', + '菌伞' => ' jùn sǎn', + '石拓' => ' shí tuò', + '施为' => ' shī wéi', + '时为' => ' shí wéi', + '铺炕' => ' pū kàng', + '劲卒' => ' jìng zú', + '笑呀' => ' xiào yā', + '劫难' => ' jié nàn', + '倒是' => ' dǎo shì', + '菌盖' => ' jùn gài', + '小曲' => ' xiǎo qǔ', + '试帖' => ' shì tiě', + '铺平' => ' pū píng', + '华佗' => ' huà tuó', + '铺垫' => ' pū diàn', + '锄头' => ' chú tou', + '销子' => ' xiāo zǐ', + '明子' => ' míng zǐ', + '华为' => ' huá wéi', + '华视' => ' huà shì', + '倒槽' => ' dǎo cáo', + '收得' => ' shōu de', + '华陀' => ' huà tuó', + '铺衬' => ' pū chèn', + '莎草' => ' suō cǎo', + '昏倒' => ' hūn dǎo', + '落价' => ' lào jià', + '晕染' => ' yùn rǎn', + '晕池' => ' yùn chí', + '俞穴' => ' shù xué', + '晕血' => ' yùn xuè', + '劈柴' => ' pǐ chái', + '晕车' => ' yùn chē', + '萹蓄' => ' biān xù', + '暑假' => ' shǔ jià', + '小纪' => ' xiǎo jǐ', + '里弄' => ' lǐ lòng', + '酸曲' => ' suān qǔ', + '星子' => ' xīng zǐ', + '酷肖' => ' kù xiāo', + '刹时' => ' chà shí', + '酬和' => ' chóu hè', + '暴晒' => ' pù shài', + '落拓' => ' luò tuò', + '配载' => ' pèi zǎi', + '配角' => ' pèi jué', + '邻舍' => ' lín shè', + '朴硝' => ' pò xiāo', + '晓得' => ' xiǎo de', + '树杈' => ' shù chà', + '钎子' => ' qiān zǐ', + '钉耙' => ' dīng pá', + '似曾' => ' sì céng', + '落藉' => ' luò jiè', + '曲阳' => ' qǔ yáng', + '本处' => ' běn chǔ', + '着衣' => ' zhuó yī', + '笋干' => ' sǔn gān', + '倒霉' => ' dǎo méi', + '所处' => ' suǒ chǔ', + '倒运' => ' dǎo yùn', + '消得' => ' xiāo de', + '曲松' => ' qǔ sōng', + '遭难' => ' zāo nàn', + '落难' => ' luò nàn', + '逢俉' => ' féng wú', + '顺子' => ' shùn zǐ', + '倒班' => ' dǎo bān', + '落魄' => ' luò tuò', + '著作' => ' zhù zuò', + '说得' => ' shuō de', + '着力' => ' zhuó lì', + '着地' => ' zháo dì', + '刷子' => ' shuā zǐ', + '着墨' => ' zhuó mò', + '那些' => ' nèi xiē', + '着急' => ' zháo jí', + '造血' => ' zào xiě', + '曲调' => ' qǔ diào', + '铺展' => ' pū zhǎn', + '松子' => ' sōng zǐ', + '铺陈' => ' pū chén', + '都灵' => ' dū líng', + '曲周' => ' qǔ zhōu', + '遛弯' => ' liù wān', + '肆应' => ' sì yìng', + '着棋' => ' zhuó qí', + '司钻' => ' sī zuàn', + '曲水' => ' qǔ shuǐ', + '过过' => ' guò guo', + '判处' => ' pàn chǔ', + '宋子' => ' sòng zǐ', + '蒜子' => ' suàn zǐ', + '过分' => ' guò fèn', + '素朴' => ' sù piáo', + '着法' => ' zhāo fǎ', + '倒蛋' => ' dǎo dàn', + '列为' => ' liè wéi', + '著书' => ' zhù shū', + '倒卖' => ' dǎo mài', + '着笔' => ' zhuó bǐ', + '算得' => ' suàn de', + '逼供' => ' bī gòng', + '着色' => ' zhuó sè', + '倒跌' => ' dǎo diē', + '当子' => ' dāng zǐ', + '懮虑' => ' yōu lù:', + '爪哇' => ' zhǎo wā', + '济宁' => ' jǐ níng', + '给水' => ' jǐ shuǐ', + '隔扇' => ' gé shān', + '少爷' => ' shào yé', + '毋宁' => ' wú nìng', + '干咳' => ' gān hāi', + '佛堂' => ' fó táng', + '爪机' => ' zhuǎ jī', + '下载' => ' xià zǎi', + '爪子' => ' zhuǎ zǐ', + '佛说' => ' fó shuō', + '女红' => ' nǚ gōng', + '尽好' => ' jìn hǎo', + '差迟' => ' chā chí', + '爪儿' => ' zhuǎ ér', + '周内' => ' zhōu nà', + '夫差' => ' fū chāi', + '尽瘁' => ' jìn cuì', + '烫发' => ' tàng fà', + '差错' => ' chā cuò', + '肘子' => ' zhǒu zǐ', + '尽美' => ' jìn měi', + '湾仔' => ' wān zǎi', + '灾难' => ' zāi nàn', + '牟平' => ' mù píng', + '好学' => ' hào xué', + '民乐' => ' mín yuè', + '尿泡' => ' suī pào', + '澎湖' => ' péng hú', + '哽塞' => ' gěng sè', + '更易' => ' gēng yì', + '毡子' => ' zhān zǐ', + '剪发' => ' jiǎn fà', + '供案' => ' gòng àn', + '尤为' => ' yóu wéi', + '供佛' => ' gòng fó', + '一样' => ' yí yàng', + '炮烙' => ' páo luò', + '更移' => ' gēng yí', + '高知' => ' gāo zhì', + '跟斗' => ' gēn dǒu', + '间色' => ' jiàn sè', + '为主' => ' wéi zhǔ', + '炸糕' => ' zhá gāo', + '葛洪' => ' gě hóng', + '间杂' => ' jiàn zá', + '炮制' => ' páo zhì', + '屏息' => ' bǐng xī', + '间日' => ' jiàn rì', + '父丧' => ' fù sāng', + '天呀' => ' tiān yā', + '屏气' => ' bǐng qì', + '殆尽' => ' dài jìn', + '干花' => ' gān huā', + '无爪' => ' wú zhuǎ', + '无间' => ' wú jiàn', + '舟子' => ' zhōu zǐ', + '煞是' => ' shà shì', + '煞白' => ' shà bái', + '朱干' => ' zhū gān', + '死劲' => ' sǐ jìng', + '复还' => ' fù huán', + '燕国' => ' yān guó', + '熨斗' => ' yùn dǒu', + '无着' => ' wú zhuó', + '轧空' => ' gá kōng', + '差池' => ' chā chí', + '揭帖' => ' jiē tiě', + '差役' => ' chāi yì', + '差别' => ' chā bié', + '殉难' => ' xùn nàn', + '照得' => ' zhào de', + '诘难' => ' jié nán', + '蠡县' => ' lǐ xiàn', + '特调' => ' tè tiáo', + '少府' => ' shào fǔ', + '干耗' => ' gān hào', + '干粪' => ' gān fèn', + '天哪' => ' tiān na', + '片儿' => ' piān er', + '天子' => ' tiān zǐ', + '牛饮' => ' niú yìn', + '牛只' => ' níu zhī', + '佛手' => ' fó shǒu', + '不了' => ' bù liǎo', + '牛仔' => ' niú zǎi', + '尽然' => ' jìn rán', + '牙行' => ' yá háng', + '牙冠' => ' yá guàn', + '片子' => ' piān zi', + '尽人' => ' jìn rén', + '干犯' => ' gān fàn', + '干裂' => ' gān liè', + '轴子' => ' zhóu zǐ', + '燕麦' => ' yān mài', + '差价' => ' chā jià', + '烟斗' => ' yān dǒu', + '叫子' => ' jiào zǐ', + '酵子' => ' jiào zǐ', + '交子' => ' jiāo zǐ', + '骄子' => ' jiāo zǐ', + '段子' => ' duàn zǐ', + '娇子' => ' jiāo zǐ', + '尿脬' => ' suī pāo', + '为人' => ' wéi rén', + '海蜇' => ' hǎi zhé', + '二更' => ' èr gēng', + '名子' => ' míng zǐ', + '挎斗' => ' kuà dǒu', + '问倒' => ' wèn dǎo', + '隐处' => ' yǐn chǔ', + '事假' => ' shì jià', + '抹角' => ' mò jiǎo', + '童子' => ' tóng zǐ', + '游散' => ' yóu sǎn', + '抹面' => ' mò miàn', + '竭尽' => ' jié jìn', + '端子' => ' duān zǐ', + '剥除' => ' bāo chú', + '投奔' => ' tóu bèn', + '脖颈' => ' bó gěng', + '空地' => ' kòng dì', + '打烊' => ' dǎ yàng', + '打更' => ' dǎ gēng', + '干馏' => ' gān liú', + '晨曲' => ' chén qǔ', + '什锦' => ' shí jǐn', + '篷子' => ' péng zǐ', + '挑起' => ' tiǎo qǐ', + '空子' => ' kòng zi', + '阴处' => ' yīn chǔ', + '批卷' => ' pī juàn', + '栟榈' => ' bīng lǘ', + '吁请' => ' yù qǐng', + '网吧' => ' wǎng bā', + '比兴' => ' bǐ xīng', + '稍息' => ' shào xī', + '令狐' => ' líng hú', + '没顶' => ' mò dǐng', + '懒散' => ' lǎn sǎn', + '没乱' => ' mò luàn', + '戳子' => ' chuō zǐ', + '丧礼' => ' sāng lǐ', + '义兴' => ' yì xīng', + '干号' => ' gān háo', + '窝囊' => ' wō nāng', + '绿营' => ' lù yíng', + '抖搂' => ' dǒu lōu', + '干饭' => ' gān fàn', + '打哄' => ' dǎ hǒng', + '缪缪' => ' miù miù', + '兵子' => ' bīng zǐ', + '咧咧' => ' liē liē', + '柄子' => ' bǐng zǐ', + '了局' => ' liǎo jú', + '空余' => ' kòng yú', + '啜泣' => ' chuò qì', + '喝令' => ' hè lìng', + '结实' => ' jiē shi', + '母丧' => ' mǔ sāng', + '奇羡' => ' jī xiàn', + '奠都' => ' diàn dū', + '属文' => ' zhǔ wén', + '篙头' => ' gāo tou', + '皋陶' => ' gāo yáo', + '糕干' => ' gāo gān', + '膏油' => ' gào yóu', + '毒爪' => ' dú zhuǎ', + '奔头' => ' bèn tóu', + '焙干' => ' bèi gān', + '干亲' => ' gān qīn', + '校核' => ' jiào hé', + '告假' => ' gào jià', + '干人' => ' gān rén', + '干肉' => ' gān ròu', + '刚子' => ' gāng zǐ', + '巡查' => ' xún zhā', + '为难' => ' wéi nán', + '奏帖' => ' zòu tiě', + '奏乐' => ' zòu yuè', + '为着' => ' wéi zhe', + '一点' => ' yì diǎn', + '为止' => ' wéi zhǐ', + '干薪' => ' gān xīn', + '山子' => ' shān zǐ', + '山脊' => ' shān jǐ', + '配乐' => ' pèi yuè', + '鸣镝' => ' míng dí', + '空隙' => ' kòng xì', + '扯臊' => ' chě sào', + '埂子' => ' gěng zǐ', + '挑拨' => ' tiǎo bō', + '喉咽' => ' hóu yān', + '朝露' => ' zhāo lù', + '吵子' => ' chǎo zǐ', + '邮折' => ' yóu shé', + '椎骨' => ' zhuī gǔ', + '命薄' => ' mìng bó', + '什菜' => ' shí cài', + '缸子' => ' gāng zǐ', + '绊倒' => ' bàn dǎo', + '大藏' => ' dà zàng', + '差数' => ' chā shù', + '大轴' => ' dà zhòu', + '岗子' => ' gǎng zǐ', + '猪仔' => ' zhū zǎi', + '著者' => ' zhù zhě', + '浇薄' => ' jiāo bó', + '猪只' => ' zhū zhī', + '告倒' => ' gào dǎo', + '为时' => ' wéi shí', + '家什' => ' jiā shí', + '钻机' => ' zuàn jī', + '忖度' => ' cǔn duó', + '盘诘' => ' pán jié', + '打颤' => ' dǎ zhàn', + '佛殿' => ' fó diàn', + '风子' => ' fēng zǐ', + '基甸' => ' jī diàn', + '累代' => ' lěi dài', + '模样' => ' mú yàng', + '了无' => ' liǎo wú', + '直奔' => ' zhí bèn', + '等子' => ' děng zǐ', + '循分' => ' xún fèn', + '盘查' => ' pán zhā', + '蜾蠃' => ' guǒ luǒ', + '戥子' => ' děng zǐ', + '盘倒' => ' pán dǎo', + '了得' => ' liǎo de', + '尽饱' => ' jìn bǎo', + '镫子' => ' dèng zǐ', + '尽头' => ' jìn tóu', + '累加' => ' lěi jiā', + '执拗' => ' zhí niù', + '省悟' => ' xǐng wù', + '的应' => ' de yìng', + '子棉' => ' zǐ mián', + '姐姐' => ' jiě jie', + '垣曲' => ' yuán qǔ', + '滑倒' => ' huá dǎo', + '混球' => ' hún qíu', + '子痫' => ' zǐ xián', + '子平' => ' zǐ píng', + '子弦' => ' zǐ xián', + '混和' => ' hùn huò', + '行伍' => ' háng wǔ', + '杭育' => ' háng yō', + '行子' => ' háng zǐ', + '宁都' => ' níng dū', + '子星' => ' zǐ xīng', + '子埝' => ' zǐ niàn', + '过淋' => ' guò lìn', + '国难' => ' guó nàn', + '准的' => ' zhǔn dì', + '贵处' => ' guì chǔ', + '妹妹' => ' mèi mei', + '渺子' => ' miǎo zǐ', + '归处' => ' guī chǔ', + '奇零' => ' jī líng', + '子囊' => ' zǐ náng', + '子陵' => ' zǐ líng', + '子明' => ' zǐ míng', + '锅伙' => ' guō huo', + '得用' => ' de yòng', + '盼头' => ' pàn tou', + '浅薄' => ' qiǎn bó', + '报载' => ' bào zǎi', + '骶椎' => ' dǐ zhuī', + '复兴' => ' fù xīng', + '尽言' => ' jìn yán', + '报帖' => ' bào tiě', + '尽致' => ' jìn zhì', + '朝暮' => ' zhāo mù', + '得亏' => ' děi kuī', + '尽数' => ' jìn shù', + '尽职' => ' jìn zhí', + '尽是' => ' jìn shì', + '唠唠' => ' lào lào', + '勒兵' => ' lè bīng', + '得着' => ' de zháo', + '落架' => ' lào jià', + '尽皆' => ' jìn jiē', + '甸子' => ' diàn zǐ', + '得性' => ' de xìng', + '得行' => ' de xíng', + '荡子' => ' dàng zǐ', + '挡子' => ' dǎng zǐ', + '倒板' => ' dǎo bǎn', + '曾波' => ' zēng bō', + '念佛' => ' niàn fó', + '唠扯' => ' lào chě', + '颠仆' => ' diān pú', + '的真' => ' dí zhēn', + '樵子' => ' qiáo zǐ', + '等得' => ' děng de', + '累时' => ' lěi shí', + '乐队' => ' yuè duì', + '得能' => ' de néng', + '得请' => ' de qǐng', + '乐音' => ' yuè yīn', + '标的' => ' biāo dì', + '累世' => ' lěi shì', + '得幸' => ' de xìng', + '了不' => ' liǎo bù', + '场儿' => ' chǎng r', + '盔头' => ' kuī tou', + '狼子' => ' láng zǐ', + '琅邪' => ' láng yá', + '后头' => ' hòu tou', + '电发' => ' diàn fà', + '尽心' => ' jìn xīn', + '得当' => ' dé dàng', + '电磨' => ' diàn mò', + '后燕' => ' hòu yān', + '店子' => ' diàn zǐ', + '癫子' => ' diān zǐ', + '拉纤' => ' lā qiàn', + '混蛋' => ' hún dàn', + '子桑' => ' zǐ sāng', + '害臊' => ' hài sào', + '侯氏' => ' hòu shì', + '回煞' => ' huí shà', + '一定' => ' yí dìng', + '好施' => ' hào shī', + '嫌恶' => ' xián wù', + '钻塔' => ' zuàn tǎ', + '黑煞' => ' hēi shà', + '子贡' => ' zǐ gòng', + '画帖' => ' huà tiè', + '侯家' => ' hòu jiā', + '泌阳' => ' bì yáng', + '互见' => ' hù xiàn', + '回弹' => ' huí tán', + '化为' => ' huà wéi', + '左肋' => ' zuǒ lèi', + '泄露' => ' xiè lòu', + '鹄望' => ' hú wàng', + '油炸' => ' yóu zhá', + '孟子' => ' mèng zǐ', + '孝子' => ' xiào zǐ', + '孔子' => ' kǒng zǐ', + '泊松' => ' bó sōng', + '洪佛' => ' hóng fó', + '红子' => ' hóng zǐ', + '密缝' => ' mì féng', + '寒假' => ' hán jià', + '洗马' => ' xiǎn mǎ', + '獾子' => ' huān zǐ', + '子层' => ' zǐ céng', + '浮漂' => ' fú piāo', + '宫掖' => ' gōng yè', + '海难' => ' hǎi nàn', + '钻具' => ' zuàn jù', + '浪子' => ' làng zǐ', + '流血' => ' liú xiě', + '流干' => ' líu gān', + '没收' => ' mò shōu', + '和药' => ' huò yào', + '子房' => ' zǐ fáng', + '沦为' => ' lún wéi', + '环子' => ' huán zǐ', + '沉没' => ' chén mò', + '子宫' => ' zǐ gōng', + '子丑' => ' zǐ chǒu', + '子京' => ' zǐ jīng', + '子婴' => ' zǐ yīng', + '子真' => ' zǐ zhēn', + '婚假' => ' hūn jià', + '宁可' => ' nìng kě', + '一块' => ' yí kuài', + '寒舍' => ' hán shè', + '子网' => ' zǐ wǎng', + '洋脊' => ' yáng jǐ', + '子乔' => ' zǐ qiáo', + '伽蓝' => ' qié lán', + '怪得' => ' guài de', + '漂泊' => ' piāo bó', + '乖剌' => ' guāi là', + '漂砾' => ' piāo lì', + '漂移' => ' piāo yí', + '家舍' => ' jiā shè', + '椎体' => ' zhuī tǐ', + '少妇' => ' shào fù', + '少女' => ' shào nǚ', + '家累' => ' jiā lěi', + '棘爪' => ' jí zhuǎ', + '满处' => ' mǎn chǔ', + '气钻' => ' qì zuàn', + '沤凼' => ' òu dàng', + '狗舍' => ' gǒu shè', + '漏斗' => ' lòu dǒu', + '夹被' => ' jiá bèi', + '好斗' => ' hào dòu', + '卓子' => ' zhuó zǐ', + '一更' => ' yī gēng', + '汗国' => ' hán guó', + '乖子' => ' guāi zǐ', + '溶没' => ' róng mò', + '瓜蔓' => ' guā wàn', + '挂斗' => ' guà dǒu', + '子洲' => ' zǐ zhōu', + '柞蚕' => ' zuò cán', + '泰斗' => ' tài dǒu', + '宜兴' => ' yí xīng', + '横逆' => ' hèng nì', + '孱头' => ' càn tou', + '子产' => ' zǐ chǎn', + '官子' => ' guān zǐ', + '泥守' => ' nì shǒu', + '环伺' => ' huán sì', + '子精' => ' zǐ jīng', + '泡货' => ' pāo huò', + '泥泞' => ' ní nìng', + '自供' => ' zì gòng', + '潜没' => ' qián mò', + '婊子' => ' biǎo zǐ', + '好高' => ' hào gāo', + '鼓角' => ' gǔ jiǎo', + '咕隆' => ' gū lōng', + '漂浮' => ' piāo fú', + '漂洗' => ' piǎo xǐ', + '给养' => ' jǐ yǎng', + '谷坊' => ' gǔ fáng', + '继兴' => ' jì xīng', + '固着' => ' gù zhuó', + '臊气' => ' sào qì', + '铺盖' => ' pū gài', + '枯萎' => ' kū wěi', + '图子' => ' tú zǐ', + '激子' => ' jī zǐ', + '局子' => ' jú zǐ', + '谱曲' => ' pǔ qǔ', + '一起' => ' yì qǐ', + '一路' => ' yí lù', + '薄雾' => ' bó wù', + '五子' => ' wǔ zǐ', + '谱子' => ' pǔ zǐ', + '西曲' => ' xī qǔ', + '栖栖' => ' xī xī', + '奴仆' => ' nú pú', + '熬稃' => ' āo fū', + '热呼' => ' rè hu', + '差讹' => ' chā é', + '毂辘' => ' gū lù', + '跛子' => ' bǒ zǐ', + '跂訾' => ' qǐ zǐ', + '夫子' => ' fū zǐ', + '薄利' => ' bó lì', + '子堤' => ' zǐ dī', + '姑子' => ' gū zǐ', + '兀秃' => ' wū tū', + '屈曲' => ' qū qǔ', + '系子' => ' xì zǐ', + '奇技' => ' qí jì', + '万俟' => ' mò qí', + '偶遇' => ' ǒu yù', + '喜得' => ' xǐ de', + '细发' => ' xì fà', + '套儿' => ' tào r', + '母子' => ' mǔ zǐ', + '薄暮' => ' bó mù', + '无似' => ' wú sì', + '薄暗' => ' bó àn', + '苏打' => ' sū dá', + '屋脊' => ' wū jǐ', + '贾客' => ' gǔ kè', + '薄技' => ' bó jì', + '漯河' => ' tà hé', + '奇偶' => ' jī ǒu', + '於菟' => ' wū tú', + '杌子' => ' wù zǐ', + '女子' => ' nǚ zǐ', + '女仆' => ' nǚ pú', + '阁子' => ' gé zǐ', + '葛麻' => ' gě má', + '息子' => ' xī zǐ', + '股子' => ' gǔ zǐ', + '薄礼' => ' bó lǐ', + '子弟' => ' zǐ dì', + '子叶' => ' zǐ yè', + '独得' => ' dú de', + '酷似' => ' kù sì', + '都护' => ' dū hù', + '曲子' => ' qǔ zi', + '厄难' => ' è nàn', + '度曲' => ' dù qǔ', + '衣子' => ' yī zǐ', + '痦子' => ' wù zǐ', + '不义' => ' bú yì', + '袄子' => ' ǎo zǐ', + '都司' => ' dū sī', + '鹤发' => ' hè fà', + '子路' => ' zǐ lù', + '西子' => ' xī zǐ', + '西打' => ' xī dá', + '蛤蛎' => ' gé lì', + '寄子' => ' jì zǐ', + '医卜' => ' yī bǔ', + '寄与' => ' jì yú', + '卒子' => ' zú zǐ', + '克勒' => ' kè lè', + '畜牧' => ' xù mù', + '自个' => ' zì gě', + '鸡子' => ' jī zǐ', + '汩没' => ' gǔ mò', + '巨擘' => ' jù bò', + '骨碌' => ' gū lù', + '古佛' => ' gǔ fó', + '语塞' => ' yǔ sè', + '武曲' => ' wǔ qǔ', + '起子' => ' qǐ zǐ', + '语域' => ' yǔ yù', + '穄子' => ' jì zǐ', + '虎子' => ' hǔ zǐ', + '曲艺' => ' qǔ yì', + '薄地' => ' bó dì', + '子安' => ' zǐ ān', + '桴子' => ' fú zǐ', + '子部' => ' zǐ bù', + '机子' => ' jī zǐ', + '浮子' => ' fú zǐ', + '附子' => ' fù zǐ', + '嘎子' => ' gǎ zǐ', + '婀娜' => ' ē nuó', + '迪吧' => ' dí bā', + '负荷' => ' fù hè', + '薄荷' => ' bò he', + '淤塞' => ' yū sè', + '字模' => ' zì mú', + '哇啦' => ' wā lā', + '瓦剌' => ' wǎ là', + '佛母' => ' fó mǔ', + '子么' => ' zǐ mǒ', + '佛历' => ' fó lì', + '佛力' => ' fó lì', + '佛理' => ' fó lǐ', + '辈儿' => ' bèi r', + '子母' => ' zǐ mǔ', + '佛偈' => ' fó jì', + '麸子' => ' fū zǐ', + '羁勒' => ' jī lè', + '佛骨' => ' fó gǔ', + '子墨' => ' zǐ mò', + '盖儿' => ' gài r', + '佛曲' => ' fó qǔ', + '妻子' => ' qī zǐ', + '差额' => ' chā é', + '屉子' => ' tì zǐ', + '剃发' => ' tì fà', + '佛土' => ' fó tǔ', + '牙子' => ' yá zǐ', + '的子' => ' de zǐ', + '籍没' => ' jí mò', + '扒鸡' => ' pá jī', + '古都' => ' gǔ dū', + '不敷' => ' bù fū', + '体己' => ' tī ji', + '怒发' => ' nù fà', + '怒喝' => ' nù hè', + '案子' => ' àn zǐ', + '脉脉' => ' mò mò', + '瓯子' => ' ōu zǐ', + '组曲' => ' zǔ qǔ', + '派司' => ' pā sī', + '昵比' => ' nì bì', + '筢子' => ' pá zǐ', + '卜卜' => ' bǔ bǔ', + '撒督' => ' sǎ dū', + '撒播' => ' sǎ bō', + '发屋' => ' fà wū', + '发丝' => ' fà sī', + '趵趵' => ' bō bō', + '咖喱' => ' gā lí', + '胡佛' => ' hú fó', + '啪啦' => ' pā lā', + '於乎' => ' wū hū', + '特勒' => ' tè lè', + '夫夫' => ' fú fū', + '末子' => ' mò zǐ', + '武都' => ' wǔ dū', + '迷糊' => ' mí hu', + '独子' => ' dú zǐ', + '希腊' => ' xī là', + '辣子' => ' là zǐ', + '大雅' => ' dà yá', + '子期' => ' zǐ qī', + '狸子' => ' lí zǐ', + '帕子' => ' pà zǐ', + '葛摩' => ' gě mó', + '子息' => ' zǐ xī', + '子奇' => ' zǐ qí', + '大都' => ' dà dū', + '帝都' => ' dì dū', + '迤逦' => ' yǐ lǐ', + '哥子' => ' gē zǐ', + '席勒' => ' xí lè', + '带儿' => ' dài r', + '无得' => ' wú de', + '娃子' => ' wá zǐ', + '六安' => ' lù ān', + '子午' => ' zǐ wǔ', + '沮洳' => ' jù rù', + '一意' => ' yī yì', + '踏踏' => ' tā tà', + '记得' => ' jì de', + '子鸡' => ' zǐ jī', + '尉犁' => ' yù lí', + '父子' => ' fù zǐ', + '爷爷' => ' yé ye', + '妮子' => ' nī zǐ', + '佛子' => ' fó zǐ', + '辟谷' => ' bì gǔ', + '娃娃' => ' wá wa', + '太阿' => ' tài ē', + '哈巴' => ' hǎ bā', + '子兮' => ' zǐ xī', + '觑糊' => ' qù hu', + '一度' => ' yí dù', + '哈呀' => ' hā yā', + '理发' => ' lǐ fà', + '泰阿' => ' tài ē', + '巨贾' => ' jù gǔ', + '逆子' => ' nì zǐ', + '玛曲' => ' mǎ qǔ', + '居积' => ' jū jī', + '覆没' => ' fù mò', + '蛤蜊' => ' gé lí', + '夜曲' => ' yè qǔ', + '哀子' => ' āi zǐ', + '龟兹' => ' qiū cí', + '角色' => ' jué sè', + '湾泊' => ' wān bó', + '鼻咽' => ' bí yān', + '吆喝' => ' yāo he', + '齱齵' => ' zōu yú', + '瓦舍' => ' wǎ shè', + '解法' => ' xiè fǎ', + '瓦刀' => ' wà dāo', + '崴泥' => ' wēi ní', + '要得' => ' yào de', + '崴子' => ' wēi zǐ', + '麇集' => ' qún jí', + '丽致' => ' lí zhì', + '要击' => ' yāo jī', + '要末' => ' yào me', + '盐都' => ' yán dū', + '叱喝' => ' chì hè', + '核查' => ' hé zhā', + '可汗' => ' kè hán', + '帵子' => ' wān zǐ', + '宛似' => ' wǎn sì', + '外子' => ' wài zǐ', + '角抵' => ' jué dǐ', + '叱呵' => ' chì hē', + '骰子' => ' tóu zǐ', + '琴曲' => ' qín qǔ', + '欸乃' => ' ǎi nǎi', + '驳倒' => ' bó dǎo', + '吐血' => ' tù xiě', + '句读' => ' jù dòu', + '掸子' => ' dǎn zǐ', + '骨头' => ' gú tou', + '凯撒' => ' kǎi sǎ', + '投得' => ' tóu de', + '吐泻' => ' tù xiè', + '要子' => ' yào zǐ', + '血塞' => ' xuè sè', + '衣甲' => ' yì jiǎ', + '替角' => ' tì jué', + '骨殖' => ' gǔ shi', + '论语' => ' lún yǔ', + '韦曲' => ' wéi qǔ', + '驮子' => ' duò zǐ', + '试液' => ' shì yè', + '高丽' => ' gāo lí', + '摩莎' => ' mó suō', + '亲子' => ' qīn zǐ', + '觉得' => ' jué de', + '驼子' => ' tuó zǐ', + '合为' => ' hé wéi', + '魔难' => ' mó nàn', + '褶子' => ' zhě zǐ', + '为底' => ' wéi dǐ', + '魏都' => ' wèi dū', + '可数' => ' kě shǔ', + '且夫' => ' qiě fú', + '可塞' => ' kě sài', + '记载' => ' jì zǎi', + '鬓发' => ' bìn fà', + '脱模' => ' tuō mú', + '认得' => ' rèn de', + '月子' => ' yuè zǐ', + '折子' => ' zhé zǐ', + '记为' => ' jì wéi', + '诸葛' => ' zhū gě', + '割舍' => ' gē shè', + '铁勒' => ' tiě lè', + '卑鄙' => ' bēi bǐ', + '列子' => ' liè zǐ', + '阿亨' => ' a hēng', + '阻难' => ' zǔ nàn', + '服事' => ' fú shi', + '里头' => ' lǐ tou', + '角力' => ' jué lì', + '合著' => ' hé zhù', + '鲍耶' => ' bào yē', + '鹄候' => ' hú hòu', + '阿顺' => ' ē shùn', + '托子' => ' tuō zǐ', + '入月' => ' rù yuè', + '囤聚' => ' tún jù', + '屯堡' => ' tún pù', + '腿子' => ' tuǐ zǐ', + '发式' => ' fà shì', + '发带' => ' fà dài', + '入肉' => ' rù ròu', + '切末' => ' qiē mò', + '发菜' => ' fà cài', + '袒裼' => ' tǎn xī', + '为乐' => ' wéi lè', + '褪去' => ' tùn qù', + '为力' => ' wéi lì', + '一只' => ' yì zhī', + '推磨' => ' tuī mò', + '诱掖' => ' yòu yè', + '袍子' => ' páo zǐ', + '撒门' => ' sǎ mén', + '诸子' => ' zhū zǐ', + '都督' => ' dū du', + '子细' => ' zǐ xì', + '朴子' => ' pò zǐ', + '服服' => ' fú fu', + '里脊' => ' lǐ jǐ', + '那麽' => ' nà me', + '鄙薄' => ' bǐ bó', + '兀自' => ' wū zì', + '何似' => ' hé sì', + '那末' => ' nà me', + '那曲' => ' nǎ qū', + '蝲蛄' => ' là gǔ', + '疑似' => ' yí sì', + '补给' => ' bǔ jǐ', + '饵子' => ' ěr zǐ', + '子女' => ' zǐ nǚ', + '歌曲' => ' gē qǔ', + '嫡子' => ' dí zǐ', + '喔喔' => ' wō wō', + '苏子' => ' sū zǐ', + '俗子' => ' sú zǐ', + '蔚蔚' => ' yù yù', + '嗉子' => ' sù zǐ', + '疙疸' => ' gē da', + '泥古' => ' nì gǔ', + '几米' => ' jī mǐ', + '刻薄' => ' kè bó', + '二曲' => ' èr qǔ', + '子夜' => ' zǐ yè', + '法子' => ' fǎ zǐ', + '歌子' => ' gē zǐ', + '虾蟆' => ' há ma', + '咔叽' => ' kǎ jī', + '不子' => ' bù zǐ', + '禾子' => ' hé zǐ', + '诃子' => ' hē zǐ', + '泥子' => ' nì zǐ', + '子粒' => ' zǐ lì', + '次子' => ' cì zǐ', + '粒子' => ' lì zǐ', + '宜都' => ' yí dū', + '虮子' => ' jǐ zǐ', + '犊子' => ' dú zǐ', + '蟢子' => ' xǐ zǐ', + '弟弟' => ' dì di', + '子目' => ' zǐ mù', + '都邑' => ' dū yì', + '曲奇' => ' qǔ qí', + '垡子' => ' fá zǐ', + '几率' => ' jī lǜ', + '误差' => ' wù chā', + '弟子' => ' dì zǐ', + '发际' => ' fà jì', + '呼啦' => ' hū lā', + '子嗣' => ' zǐ sì', + '子鱼' => ' zǐ yú', + '仆役' => ' pú yì', + '子句' => ' zǐ jù', + '发妻' => ' fà qī', + '坷垃' => ' kē lā', + '法曲' => ' fǎ qǔ', + '子集' => ' zǐ jí', + '俗曲' => ' sú qǔ', + '欧泊' => ' ōu bó', + '发乳' => ' fà rǔ', + '子羽' => ' zǐ yǔ', + '微曲' => ' wēi qǔ', + '古刹' => ' gǔ chà', + '投子' => ' tóu zǐ', + '只得' => ' zhǐ de', + '蛮子' => ' mán zǐ', + '蚕薄' => ' cán bó', + '骨朵' => ' gū duǒ', + '子域' => ' zǐ yù', + '四子' => ' sì zǐ', + '几欲' => ' jī yù', + '曲率' => ' qǔ lǜ', + '訾议' => ' zǐ yì', + '几案' => ' jī àn', + '曲沃' => ' qǔ wò', + '孤子' => ' gū zǐ', + '几希' => ' jī xī', + '暗堡' => ' àn pù', + '婆子' => ' pó zǐ', + '几乎' => ' jī hū', + '窝子' => ' wō zǐ', + '子婿' => ' zǐ xù', + '子虚' => ' zǐ xū', + '都德' => ' dū dé', + '具足' => ' jù zú', + '曲目' => ' qǔ mù', + '举子' => ' jǔ zǐ', + '巨子' => ' jù zǐ', + '季子' => ' jì zǐ', + '瓠子' => ' hù zǐ', + '坷拉' => ' kē lā', + '序曲' => ' xù qǔ', + '素子' => ' sù zǐ', + '鹄立' => ' hú lì', + '糢糊' => ' mó hu', + '咖哩' => ' kā li', + '半打' => ' bàn dá', + '日没' => ' rì mò', + '露茜' => ' lù xī', + '撒子' => ' sā zǐ', + '阿诺' => ' a nuò', + '卜辞' => ' bǔ cí', + '铺路' => ' pū lù', + '锯子' => ' jù zǐ', + '鏊子' => ' ào zǐ', + '的卢' => ' dì lú', + '樀樀' => ' dí dí', + '嘀哒' => ' dī dā', + '劲拔' => ' jìng bá', + '乐得' => ' lè de', + '乐呵' => ' lè hē', + '目的' => ' mù dì', + '得色' => ' de sè', + '模糊' => ' mó hu', + '模子' => ' mú zǐ', + '勒子' => ' lè zǐ', + '模具' => ' mú jù', + '模似' => ' mó sì', + '复辟' => ' fù bì', + '去得' => ' qù de', + '圩日' => ' xū rì', + '勒逼' => ' lè bī', + '吗哪' => ' mǎ nǎ', + '姁姁' => ' xū xū', + '离子' => ' lí zǐ', + '雨子' => ' yǔ zǐ', + '嗳腐' => ' ài fǔ', + '科克' => ' kē kè', + '余裕' => ' yú yù', + '秕子' => ' bǐ zǐ', + '秘鲁' => ' bì lǔ', + '租子' => ' zū zǐ', + '余吾' => ' yú wú', + '摊儿' => ' tān r', + '故都' => ' gù dū', + '伛偻' => ' yǔ lǚ', + '稀薄' => ' xī bó', + '须得' => ' xū de', + '没地' => ' mò dì', + '戊子' => ' wù zǐ', + '戏子' => ' xì zǐ', + '戏曲' => ' xì qǔ', + '没入' => ' mò rù', + '自给' => ' zì jǐ', + '于都' => ' yú dū', + '勒抑' => ' lè yì', + '麻麻' => ' mā ma', + '卜居' => ' bǔ jū', + '勒马' => ' lè mǎ', + '坯模' => ' pī mú', + '阿斗' => ' ā dǒu', + '阿森' => ' a sēn', + '鞑子' => ' dá zǐ', + '达子' => ' dá zǐ', + '搭子' => ' dā zǐ', + '矮子' => ' ǎi zǐ', + '博得' => ' bó de', + '大佛' => ' dà fó', + '铺子' => ' pù zǐ', + '南无' => ' nā mó', + '答答' => ' dā dā', + '噶嗒' => ' gá tà', + '砝码' => ' fǎ mǎ', + '舞曲' => ' wǔ qǔ', + '破的' => ' pò dì', + '咋呀' => ' zǎ yā', + '俟机' => ' sì jī', + '附和' => ' fù hè', + '卜课' => ' bǔ kè', + '卜骨' => ' bǔ gǔ', + '铺叙' => ' pū xù', + '得按' => ' de àn', + '李子' => ' lǐ zǐ', + '堵塞' => ' dǔ sè', + '铺砌' => ' pū qì', + '棵子' => ' kē zǐ', + '锞子' => ' kè zǐ', + '剂子' => ' jì zǐ', + '口哦' => ' kǒu ò', + '钜子' => ' jù zǐ', + '墨子' => ' mò zǐ', + '钩儿' => ' gōu r', + '塞责' => ' sè zé', + '劲儿' => ' jìn r', + '锔子' => ' jū zǐ', + '徒裼' => ' tú xī', + '弥勒' => ' mí lè', + '菥蓂' => ' xī mì', + '塔扎' => ' tǎ zā', + '百色' => ' bǎi sè', + '拉忽' => ' lǎ hū', + '役畜' => ' yì xù', + '剌剌' => ' là là', + '砬子' => ' lá zǐ', + '革吉' => ' gé jí', + '预卜' => ' yù bǔ', + '得也' => ' de yě', + '壳儿' => ' ké r', + '哦呀' => ' ò yā', + '阿谀' => ' ē yú', + '地儿' => ' dì r', + '抹额' => ' mò é', + '嗯啊' => ' ng ā', + '肚儿' => ' dǔ r', + '子儿' => ' zǐ r', + '阿附' => ' ē fù', + '绩溪' => ' jì xī', + '理儿' => ' lǐ r', + '阿堵' => ' ē dǔ', + '尜儿' => ' gá r', + '啊哟' => ' ā yō', + '挨饿' => ' ái è', + '皮儿' => ' pí r', + '啊呀' => ' ā yā', + '阿里' => ' a lǐ', + '杂沓' => ' zá tà', + '辱没' => ' rǔ mò', + '集子' => ' jí zǐ', + '呕气' => ' òu qì', + '阿卡' => ' a kǎ', + '阿坝' => ' a bà', + '嘀嗒' => ' dī dā', + '三都' => ' sān dū', + '圆晕' => ' yuán yùn', + '都安' => ' dū ān', + '曾家' => ' zēng jiā', + '曾姓' => ' zēng xìng', + '姓曾' => ' xìng zēng', + '便宜' => ' pián yí', + '长阳' => ' cháng yáng', + '呃呃' => ' e e', + '吖吖' => ' ā ā', + '阿耶' => ' ā yē', + '阿巴' => ' a bā', + '阿苏' => ' a sū', + '囮子' => ' é zǐ', + '阿瑟' => ' a sè', + '阿佤' => ' a wǎ', + '巴阿' => ' bā a', + '腌臜' => ' ā zā', + '啊哈' => ' ā hā', + '阿比' => ' ē bǐ', + '末儿' => ' mò r', + '阿的' => ' ā dì', + '嗣子' => ' sì zǐ', + '呕吐' => ' ǒu tù', + '把儿' => ' bà er', + '谜子' => ' mí zǐ', + '扒犁' => ' pá li', + '靡丽' => ' mǐ lì', + '屈子' => ' qū zǐ', + '靡靡' => ' mǐ mǐ', + '浴佛' => ' yù fó', + '玉佛' => ' yù fó', + '卧佛' => ' wò fó', + '欲得' => ' yù de', + '沵迤' => ' mǐ yǐ', + '靶子' => ' bǎ zǐ', + '秃子' => ' tū zǐ', + '喜子' => ' xǐ zǐ', + '胆儿' => ' dǎn r', + '腻子' => ' nì zǐ', + '哑子' => ' yǎ zǐ', + '曲谱' => ' qǔ pǔ', + '扶掖' => ' fú yè', + '莫得' => ' mò de', + '栖息' => ' qī xī', + '冒顿' => ' mò dú', + '靺鞨' => ' mò hé', + '虚子' => ' xū zǐ', + '玉子' => ' yù zǐ', + '嘎啦' => ' gā lā', + '撒布' => ' sǎ bù', + '呜咽' => ' wū yè', + '磨子' => ' mò zǐ', + '鹿子' => ' lù zǐ', + '碌曲' => ' lù qǔ', + '恶煞' => ' è shà', + '嗳气' => ' ài qì', + '恶心' => ' ě xīn', + '恶嗪' => ' ě qín', + '瘄子' => ' cù zǐ', + '粗呢' => ' cū ní', + '刺啦' => ' cī lā', + '麻秸' => ' má jí', + '爱子' => ' ài zǐ', + '入子' => ' rù zǐ', + '垆坶' => ' lú mù', + '孺子' => ' rú zǐ', + '呲牙' => ' zī yá', + '词曲' => ' cí qǔ', + '磨叽' => ' mò ji', + '卤子' => ' lǔ zǐ', + '乳女' => ' rǔ nǚ', + '码子' => ' mǎ zǐ', + '般若' => ' bō rě', + '杜塞' => ' dù sè', + '发髻' => ' fà jì', + '餔子' => ' bū zǐ', + '簿子' => ' bù zǐ', + '拨刺' => ' bō cī', + '呀呀' => ' yā yā', + '米芾' => ' mǐ fú', + '哑哑' => ' yā yā', + '马勒' => ' mǎ lè', + '马子' => ' mǎ zǐ', + '篦子' => ' bì zǐ', + '马尾' => ' mǎ yǐ', + '布子' => ' bù zǐ', + '拨子' => ' bō zǐ', + '堡子' => ' bǔ zi', + '补子' => ' bǔ zǐ', + '丫子' => ' yā zǐ', + '拘泥' => ' jū nì', + '哈佛' => ' hā fó', + '驹子' => ' jū zǐ', + '哇哇' => ' wā wā', + '脊骨' => ' jǐ gǔ', + '部曲' => ' bù qǔ', + '哎呀' => ' āi yā', + '簸箕' => ' bò ji', + '哈迪' => ' hǎ dí', + '把子' => ' bà zi', + '七佛' => ' qī fó', + '耶西' => ' yē xī', + '耶稣' => ' yē sū', + '一个' => ' yí gè', + '似核' => ' sì hé', + '吧女' => ' bā nǚ', + '吧嗒' => ' bā dā', + '坝子' => ' bà zǐ', + '吧唧' => ' bā jī', + '一发' => ' yī fà', + '耳子' => ' ěr zǐ', + '哈达' => ' hǎ dá', + '七个' => ' qī ge', + '吖嗪' => ' ā qín', + '佛寺' => ' fó sì', + '意得' => ' yì de', + '一得' => ' yī de', + '耙子' => ' pá zǐ', + '吟哦' => ' yín é', + '磨墨' => ' mó mò', + '魣鱼' => ' yú yú', + '婢子' => ' bì zǐ', + '箕子' => ' jī zǐ', + '曲裾' => ' qǔ jū', + '伺隙' => ' sì xì', + '给予' => ' jǐ yǔ', + '须子' => ' xū zǐ', + '佛语' => ' fó yǔ', + '须发' => ' xū fà', + '郁塞' => ' yù sè', + '披发' => ' pī fà', + '可恶' => ' kě wù', + '移易' => ' yí yì', + '胡子' => ' hú zǐ', + '仡仡' => ' yì yì', + '鱼子' => ' yú zǐ', + '胰子' => ' yí zǐ', + '挨打' => ' ái dǎ', + '挨批' => ' ái pī', + '咿呀' => ' yī yā', + '肚子' => ' dǔ zi', + '挨挤' => ' ái jǐ', + '丝柏' => ' sī bó', + '鱼肚' => ' yú dǔ', + '挨骂' => ' ái mà', + '移译' => ' yí yì', + '糊糊' => ' hū hū', + '义子' => ' yì zǐ', + '翼子' => ' yì zǐ', + '莫邪' => ' mò yé', + '衲子' => ' nà zǐ', + '壳子' => ' ké zǐ', + '牟尼' => ' mù ní', + '木模' => ' mù mú', + '披靡' => ' pī mǐ', + '曲剧' => ' qǔ jù', + '木子' => ' mù zǐ', + '抹布' => ' mā bù', + '哥哥' => ' gē ge', + '那得' => ' nà de', + '梨子' => ' lí zǐ', + '曲辞' => ' qǔ cí', + '不落' => ' bù là', + '嗳哟' => ' ài yō', + '筏子' => ' fá zǐ', + '答理' => ' dā lǐ', + '播撒' => ' bō sǎ', + '策勒' => ' cè lè', + '脯子' => ' pú zǐ', + '取得' => ' qǔ de', + '曲度' => ' qǔ dù', + '箅子' => ' bì zǐ', + '驴子' => ' lǘ zǐ', + '似乎' => ' sì hū', + '伺机' => ' sì jī', + '阿伦' => ' a lún', + '伯伯' => ' bó bo', + '呢呢' => ' ní ní', + '摸吧' => ' mō bā', + '系泊' => ' jì bó', + '吽牙' => ' ōu yá', + '继子' => ' jì zǐ', + '昳丽' => ' yì lì', + '麻力' => ' má li', + '呢子' => ' ní zǐ', + '伢子' => ' yá zǐ', + '摩撒' => ' mā sa', + '核子' => ' hé zǐ', + '伯都' => ' bó dū', + '估衣' => ' gù yī', + '摩挲' => ' mā sā', + '仆妇' => ' pú fù', + '吴子' => ' wú zǐ', + '耶鲁' => ' yē lǔ', + '仆仆' => ' pú pú', + '合子' => ' hé zǐ', + '泼剌' => ' pō là', + '伺服' => ' sì fú', + '核儿' => ' hú ér', + '棋子' => ' qí zǐ', + '鹄的' => ' gǔ dì', + '乐子' => ' lè zǐ', + '坨儿' => ' tuó r', + '得死' => ' de sǐ', + '得气' => ' de qì', + '得理' => ' de lǐ', + '乙巳' => ' yǐ sì', + '闭塞' => ' bì sè', + '丽都' => ' lì dū', + '的卡' => ' dí kǎ', + '礼佛' => ' lǐ fó', + '得度' => ' de dù', + '抹子' => ' mǒ zǐ', + '得得' => ' de de', + '地堡' => ' dì pù', + '俚曲' => ' lǐ qǔ', + '阻塞' => ' zǔ sè', + '阿丹' => ' a dān', + '里子' => ' lǐ zǐ', + '德都' => ' dé dū', + '阿来' => ' a lái', + '得地' => ' de dì', + '壶子' => ' hú zǐ', + '鹿谷' => ' lù gǔ', + '以撒' => ' yǐ sǎ', + '仆射' => ' pú yè', + '揦子' => ' lá zǐ', + '吧吧' => ' bā bā', + '佛塔' => ' fó tǎ', + '挨罚' => ' ái fá', + '埯子' => ' ǎn zǐ', + '庵子' => ' ān zǐ', + '鞍子' => ' ān zǐ', + '巴子' => ' bā zǐ', + '安子' => ' ān zǐ', + '弃子' => ' qì zǐ', + '衣被' => ' yì pī', + '栖宿' => ' qī sù', + '页子' => ' yè zǐ', + '耶耶' => ' yē yē', + '也得' => ' yě de', + '野葛' => ' yě gě', + '也似' => ' yě sì', + '耶律' => ' yē lǜ', + '七子' => ' qī zǐ', + '掖咕' => ' yē gu', + '伽马' => ' gā mǎ', + '八子' => ' bā zǐ', + '搭拉' => ' dā la', + '吉勒' => ' jí lè', + '格勒' => ' gé lè', + '呵护' => ' hē hù', + '坯子' => ' pī zǐ', + '貔子' => ' pí zǐ', + '佛祖' => ' fó zǔ', + '碧波' => ' bì bō', + '佛牙' => ' fó yá', + '一似' => ' yī sì', + '呼吁' => ' hū yù', + '佛爷' => ' fó yé', + '味儿' => ' wèi r', + '呵责' => ' hē zé', + '鮨科' => ' qí kē', + '吐沫' => ' tù mò', + '凫茈' => ' fú zǐ', + '鸭子' => ' yā zǐ', + '佛法' => ' fó fǎ', + '呵喝' => ' hē hè', + '一曲' => ' yī qǔ', + '呵呵' => ' hē hē', + '呼喝' => ' hū hè', + '婢仆' => ' bì pú', + '耶酥' => ' yē sū', + '吐蕃' => ' tǔ bō', + '半拉' => ' bàn lǎ', + '遇难' => ' yù nàn', + '只如' => ' zhī rú', + '难挨' => ' nán ái', + '彩子' => ' cǎi zǐ', + '内子' => ' nèi zǐ', + '柰子' => ' nài zǐ', + '押解' => ' yā jiè', + '哪吒' => ' né zhā', + '没世' => ' mò shì', + '抹灰' => ' mò huī', + '磨粉' => ' mò fěn', + '批假' => ' pī jià', + '扳子' => ' bān zǐ', + '不处' => ' bù chǔ', + '啦呱' => ' lā gua', + '喀什' => ' kā shí', + '打杈' => ' dǎ chà', + '泯没' => ' mǐn mò', + '打折' => ' dǎ zhé', + '喀嚓' => ' kā chā', + '缪斯' => ' miù sī', + '菜子' => ' cài zǐ', + '难弟' => ' nàn dì', + '哪个' => ' něi gè', + '咯嚓' => ' gē chā', + '妞子' => ' niū zǐ', + '拉杆' => ' lā gǎn', + '补假' => ' bǔ jià', + '拗口' => ' ào kǒu', + '拖沓' => ' tuō tà', + '拓跋' => ' tuò bá', + '呢帽' => ' ní mào', + '拓扑' => ' tuò pū', + '委蛇' => ' wēi yí', + '哇靠' => ' wā kào', + '拓拔' => ' tuò bá', + '不究' => ' bù jiù', + '咱家' => ' zá jiā', + '牛子' => ' niú zǐ', + '潘子' => ' pān zǐ', + '咳嗽' => ' ké sòu', + '咳痰' => ' ké tán', + '剥取' => ' bāo qǔ', + '拾级' => ' shè jí', + '不价' => ' bù jie', + '啪嚓' => ' pā chā', + '怒号' => ' nù háo', + '不倒' => ' bù dǎo', + '拶子' => ' zǎn zǐ', + '穇子' => ' cǎn zǐ', + '槽子' => ' cáo zǐ', + '牛肚' => ' niú dǔ', + '卡壳' => ' qiǎ ké', + '酦醅' => ' pō pēi', + '半子' => ' bàn zǐ', + '柈子' => ' bàn zǐ', + '朴刀' => ' pō dāo', + '绊子' => ' bàn zǐ', + '剥壳' => ' bāo ké', + '吧托' => ' bā tuō', + '吞没' => ' tūn mò', + '名儿' => ' míng r', + '卡具' => ' qiǎ jù', + '吸血' => ' xī xiě', + '熬菜' => ' āo cài', + '凄咽' => ' qī yān', + '八斗' => ' bā dǒu', + '吧台' => ' bā tái', + '八舍' => ' bā shè', + '插曲' => ' chā qǔ', + '提溜' => ' dī liū', + '起解' => ' qǐ jiè', + '吖啶' => ' ā dìng', + '君子' => ' jūn zǐ', + '陂陀' => ' pō tuó', + '版子' => ' bǎn zǐ', + '艚子' => ' cáo zǐ', + '拂士' => ' bì shì', + '拉呱' => ' lā guā', + '南子' => ' nán zǐ', + '抿子' => ' mǐn zǐ', + '差可' => ' chā kě', + '南曲' => ' nán qǔ', + '男仆' => ' nán pú', + '杈子' => ' chā zǐ', + '汊子' => ' chà zǐ', + '拉倒' => ' lā dǎo', + '查理' => ' zhā lǐ', + '探子' => ' tàn zǐ', + '车毂' => ' chē gū', + '炮格' => ' páo gé', + '配曲' => ' pèi qǔ', + '采邑' => ' cài yì', + '掖门' => ' yè mén', + '百子' => ' bǎi zǐ', + '含糊' => ' hán hu', + '稗子' => ' bài zǐ', + '败子' => ' bài zǐ', + '吸尽' => ' xī jìn', + '不为' => ' bù wéi', + '哇塞' => ' wā sāi', + '七煞' => ' qī shà', + '屯子' => ' tún zǐ', + '干谒' => ' gān yè', + '柑子' => ' gān zǐ', + '干子' => ' gàn zǐ', + '甘子' => ' gān zǐ', + '干租' => ' gān zū', + '套子' => ' tào zǐ', + '昆曲' => ' kūn qǔ', + '岔子' => ' chà zǐ', + '套曲' => ' tào qǔ', + '秆子' => ' gǎn zǐ', + '杆塔' => ' gǎn tǎ', + '奥什' => ' aò shí', + '奇数' => ' jī shù', + '干礼' => ' gān lǐ', + '赴难' => ' fù nàn', + '差异' => ' chā yì', + '失意' => ' shī yì', + '附载' => ' fù zǎi', + '附识' => ' fù zhì', + '夹克' => ' jiá kè', + '干没' => ' gān mò', + '赶圩' => ' gǎn xū', + '干热' => ' gān rè', + '干巴' => ' gān bā', + '荷载' => ' hè zǎi', + '子规' => ' zǐ guī', + '子孙' => ' zǐ sūn', + '黑子' => ' hēi zǐ', + '会得' => ' huì de', + '蒿子' => ' hāo zǐ', + '宿舍' => ' sù shè', + '宿分' => ' sù fèn', + '家子' => ' jiā zǐ', + '家姑' => ' jiā gū', + '害得' => ' hài de', + '干呕' => ' gān ǒu', + '子弹' => ' zǐ dàn', + '和诗' => ' hè shī', + '子时' => ' zǐ shí', + '子曰' => ' zǐ yuē', + '何为' => ' hé wéi', + '喝问' => ' hè wèn', + '子实' => ' zǐ shí', + '差距' => ' chā jù', + '鸡舍' => ' jī shè', + '呱哒' => ' guā dā', + '干碍' => ' gān ài', + '巨著' => ' jù zhù', + '哇噻' => ' wā sāi', + '好似' => ' hǎo sì', + '篙子' => ' gāo zǐ', + '歌呗' => ' gē bài', + '圪节' => ' gē jiē', + '夺得' => ' duó de', + '割切' => ' gē qiē', + '夹衣' => ' jiá yī', + '给回' => ' jǐ huí', + '居处' => ' jū chǔ', + '奶子' => ' nǎi zǐ', + '好哇' => ' hǎo wā', + '好奇' => ' hào qí', + '尾子' => ' wěi zǐ', + '蛤仔' => ' gé zǎi', + '暗查' => ' àn zhā', + '络子' => ' lào zi', + '尧都' => ' yáo dū', + '哀乐' => ' āi yuè', + '拮据' => ' jié jū', + '哀号' => ' āi háo', + '拜佛' => ' bài fó', + '臬兀' => ' niè wū', + '膏子' => ' gāo zǐ', + '好客' => ' hào kè', + '杆儿' => ' gǎn ér', + '枸橘' => ' gōu jú', + '干股' => ' gān gǔ', + '干急' => ' gān jí', + '干季' => ' gān jì', + '夹袄' => ' jiá ǎo', + '呱唧' => ' guā jī', + '属意' => ' zhǔ yì', + '羔子' => ' gāo zǐ', + '家仆' => ' jiā pú', + '购得' => ' gòu de', + '狗脊' => ' gǒu jǐ', + '好色' => ' hào sè', + '膏泽' => ' gào zé', + '夹布' => ' jiá bù', + '好恶' => ' hào wù', + '狗子' => ' gǒu zǐ', + '贾祸' => ' gǔ huò', + '锢露' => ' gù lòu', + '贾人' => ' gǔ rén', + '鼓乐' => ' gǔ yuè', + '妃子' => ' fēi zǐ', + '呱嗒' => ' guā dā', + '沟子' => ' gōu zǐ', + '推子' => ' tuī zǐ', + '炮子' => ' pào zǐ', + '子鼠' => ' zǐ shǔ', + '喝采' => ' hè cǎi', + '所得' => ' suǒ de', + '匙子' => ' chí zi', + '咪唑' => ' mǐ zuò', + '秘钥' => ' mì yuè', + '打倒' => ' dǎ dǎo', + '扒糕' => ' pá gāo', + '喝彩' => ' hè cǎi', + '喝道' => ' hè dào', + '闷气' => ' mēn qì', + '宓妃' => ' fú fēi', + '毛子' => ' máo zǐ', + '扒灰' => ' pá huī', + '扒搂' => ' bā lōu', + '扎染' => ' zā rǎn', + '才子' => ' cái zǐ', + '痴子' => ' chī zǐ', + '扒窃' => ' pá qiè', + '喷薄' => ' pēn bó', + '吗啡' => ' mǎ fēi', + '处和' => ' chǔ hé', + '庐舍' => ' lú shè', + '单薄' => ' dān bó', + '嫚骂' => ' màn mà', + '虏掠' => ' lǔ lüě', + '媒子' => ' méi zǐ', + '地窨' => ' dì yìn', + '地处' => ' dì chǔ', + '力尽' => ' lì jìn', + '得对' => ' de duì', + '得靠' => ' de kào', + '微薄' => ' wēi bó', + '喜好' => ' xǐ hào', + '闷热' => ' mēn rè', + '喷子' => ' pēn zǐ', + '糜子' => ' méi zǐ', + '单曲' => ' dān qǔ', + '戽斗' => ' hù dǒu', + '戒子' => ' jiè zǐ', + '煤核' => ' méi hú', + '懒得' => ' lǎn de', + '门把' => ' mén bà', + '没得' => ' méi de', + '毛呢' => ' máo ní', + '单个' => ' dān ge', + '锚泊' => ' máo bó', + '满子' => ' mǎn zǐ', + '路卡' => ' lù qiǎ', + '嘴子' => ' zuǐ zǐ', + '礼帖' => ' lǐ tiě', + '朱子' => ' zhū zǐ', + '处子' => ' chǔ zǐ', + '蚕子' => ' cán zǐ', + '勒戒' => ' lè jiè', + '果脯' => ' guǒ fǔ', + '自尽' => ' zì jìn', + '制曲' => ' zhì qǔ', + '空额' => ' kòng é', + '不会' => ' bú huì', + '枝子' => ' zhī zǐ', + '甲子' => ' jiǎ zǐ', + '恺撒' => ' kǎi sǎ', + '不是' => ' bú shì', + '只鸡' => ' zhī jī', + '男子' => ' nán zǐ', + '不尽' => ' bù jìn', + '款儿' => ' kuǎn r', + '幼子' => ' yòu zǐ', + '不禁' => ' bù jīn', + '倒卧' => ' dǎo wò', + '优子' => ' yōu zǐ', + '留都' => ' liú dū', + '恺弟' => ' kǎi tì', + '掠地' => ' lüě dì', + '爱好' => ' ài hào', + '嗑药' => ' kè yào', + '猝倒' => ' cù dǎo', + '陆处' => ' lù chǔ', + '篓子' => ' lǒu zǐ', + '恶少' => ' è shào', + '绺子' => ' liǔ zǐ', + '溜子' => ' liū zǐ', + '六子' => ' liù zǐ', + '情儿' => ' qíng r', + '漏子' => ' lòu zǐ', + '唠嗑' => ' lào kè', + '憨子' => ' hān zǐ', + '哗啦' => ' huā lā', + '马扎' => ' mǎ zhá', + '抹澡' => ' mā zǎo', + '马仔' => ' mǎ zǎi', + '马杆' => ' mǎ gǎn', + '麻杆' => ' má gǎn', + '滀仕' => ' xù shì', + '刺溜' => ' cī liū', + '雏子' => ' chú zǐ', + '落发' => ' luò fà', + '道子' => ' dào zǐ', + '坋粒' => ' fèn lì', + '扫把' => ' sào bǎ', + '底处' => ' dǐ chǔ', + '挨斗' => ' ái dòu', + '贝勒' => ' bèi lè', + '呵禁' => ' hē jìn', + '捏脊' => ' niē jǐ', + '贝子' => ' bèi zǐ', + '褙子' => ' bèi zǐ', + '背子' => ' bēi zi', + '锛子' => ' bēn zǐ', + '北曲' => ' běi qǔ', + '车仆' => ' chē pú', + '舍得' => ' shè de', + '喜帖' => ' xǐ tiě', + '大说' => ' dà yuè', + '恨恶' => ' hèn wù', + '答允' => ' dā yǔn', + '待得' => ' dài de', + '赕佛' => ' dǎn fó', + '恁么' => ' rèn me', + '急难' => ' jí nàn', + '恰似' => ' qià sì', + '蛋子' => ' dàn zǐ', + '呵斥' => ' hē chì', + '呵叱' => ' hē chì', + '回鹘' => ' huí hú', + '挨克' => ' ái kēi', + '宝子' => ' bǎo zǐ', + '披散' => ' pī sǎn', + '挨揍' => ' ái zòu', + '咋舌' => ' zé shé', + '挨宰' => ' ái zǎi', + '和洽' => ' hé qià', + '芘芣' => ' pí fǒu', + '和牌' => ' hú pái', + '咋呼' => ' zhā hū', + '膍胵' => ' pí zhì', + '挨延' => ' ái yán', + '瘪子' => ' biě zǐ', + '别子' => ' bié zǐ', + '喷撒' => ' pēn sǎ', + '胚子' => ' pēi zǐ', + '咔嚓' => ' kā chā', + '僻处' => ' pì chǔ', + '呢喃' => ' ní nán', + '鼻血' => ' bí xiě', + '呼号' => ' hū háo', + '保子' => ' bǎo zǐ', + '刀把' => ' dāo bà', + '因子' => ' yīn zǐ', + '在乎' => ' zài hu', + '累次' => ' lěi cì', + '得月' => ' de yuè', + '得这' => ' de zhè', + '檑木' => ' lèi mù', + '肋木' => ' lèi mù', + '得时' => ' de shí', + '肋膜' => ' lèi mó', + '勒掯' => ' lè kèn', + '得使' => ' de shǐ', + '累及' => ' lěi jí', + '勒石' => ' lè shí', + '得位' => ' de wèi', + '勒派' => ' lè pài', + '埋没' => ' mái mò', + '叨咕' => ' dáo gu', + '坎子' => ' kǎn zǐ', + '得来' => ' de lái', + '必得' => ' bì děi', + '德干' => ' dé gān', + '土著' => ' tǔ zhù', + '礼乐' => ' lǐ yuè', + '倒牙' => ' dǎo yá', + '坨子' => ' tuó zǐ', + '得数' => ' de shù', + '到得' => ' dào de', + '答茬' => ' dā chá', + '倒底' => ' dǎo dǐ', + '囤积' => ' tún jī', + '回纥' => ' huí hé', + '倒阁' => ' dǎo gé', + '淋滤' => ' lìn lǜ', + '大溜' => ' dà liù', + '遛马' => ' liù mǎ', + '六路' => ' liù lù', + '锉子' => ' cuò zǐ', + '瘩背' => ' dá bèi', + '六个' => ' liù ge', + '国都' => ' guó dū', + '大落' => ' dà luō', + '噶厦' => ' gá xià', + '吓唬' => ' xià hu', + '大哗' => ' dà huá', + '大尽' => ' dà jìn', + '檩子' => ' lǐn zǐ', + '悉数' => ' xī shǔ', + '打擂' => ' dǎ lèi', + '大斗' => ' dà dǒu', + '矬子' => ' cuó zǐ', + '字帖' => ' zì tiè', + '胡为' => ' hú wéi', + '阇黎' => ' shé lí', + '余切' => ' yú qiē', + '参差' => ' cēn cī', + '贴吧' => ' tiē bā', + '贩子' => ' fàn zǐ', + '谜儿' => ' mèi ér', + '铁耙' => ' tiě pá', + '谩骂' => ' màn mà', + '识得' => ' shí de', + '馓子' => ' sǎn zǐ', + '余干' => ' yú gān', + '饿莩' => ' è piǎo', + '鞋子' => ' xié zǐ', + '誉为' => ' yù wéi', + '出没' => ' chū mò', + '叔子' => ' shū zǐ', + '责难' => ' zé nàn', + '食肆' => ' shí sì', + '类似' => ' lèi sì', + '击倒' => ' jī dǎo', + '秋子' => ' qiū zǐ', + '球子' => ' qiú zǐ', + '豁达' => ' huò dá', + '曲坛' => ' qǔ tán', + '摆子' => ' bǎi zǐ', + '颓靡' => ' tuí mǐ', + '颇为' => ' pō wéi', + '卖卜' => ' mài bǔ', + '头发' => ' tóu fà', + '担子' => ' dàn zi', + '质子' => ' zhì zǐ', + '赤子' => ' chì zǐ', + '曲牌' => ' qǔ pái', + '书脊' => ' shū jǐ', + '走子' => ' zǒu zǐ', + '头儿' => ' tou er', + '曲式' => ' qǔ shì', + '擦干' => ' cā gān', + '担搁' => ' dān ge', + '贲临' => ' bì lín', + '参与' => ' cān yù', + '担荷' => ' dān hè', + '树子' => ' shù zǐ', + '擘划' => ' bò huà', + '擘画' => ' bò huà', + '擘开' => ' bò kāi', + '屈折' => ' qū shé', + '跂坐' => ' qì zuò', + '曲包' => ' qǔ bāo', + '豆皀' => ' dòu bī', + '撒施' => ' sǎ shī', + '踏查' => ' tà zhā', + '近似' => ' jìn sì', + '散发' => ' sàn fà', + '若夫' => ' ruò fú', + '划子' => ' huá zǐ', + '陪都' => ' péi dū', + '切腹' => ' qiē fù', + '印子' => ' yìn zǐ', + '即为' => ' jí wéi', + '踏实' => ' tā shi', + '厌薄' => ' yàn bó', + '贪得' => ' tān de', + '踶跂' => ' dì zhī', + '群子' => ' qún zǐ', + '厌恶' => ' yàn wù', + '蹦儿' => ' bèng r', + '切入' => ' qiē rù', + '热和' => ' rè huo', + '摊薄' => ' tān bó', + '轧机' => ' zhá jī', + '陶子' => ' táo zǐ', + '热轧' => ' rè zhá', + '乳臭' => ' rǔ xiù', + '辟邪' => ' bì xié', + '曲池' => ' qǔ chí', + '散居' => ' sǎn jū', + '貌似' => ' mào sì', + '出落' => ' chū là', + '扑倒' => ' pū dǎo', + '除子' => ' chú zǐ', + '踅摸' => ' xué mo', + '面儿' => ' miàn r', + '载入' => ' zǎi rù', + '载籍' => ' zǎi jí', + '鸡肋' => ' jī lèi', + '隽誉' => ' jùn yù', + '散曲' => ' sǎn qǔ', + '载荷' => ' zài hè', + '隽语' => ' jùn yǔ', + '卡子' => ' qiǎ zi', + '儒艮' => ' rú gèn', + '雅乐' => ' yǎ yuè', + '雅什' => ' yǎ shí', + '隐没' => ' yǐn mò', + '日晕' => ' rì yùn', + '切牙' => ' qiē yá', + '轗轲' => ' kǎn kě', + '撒花' => ' sǎ huā', + '贴子' => ' tiē zǐ', + '露底' => ' lòu dǐ', + '卜问' => ' bǔ wèn', + '三个' => ' sān ge', + '索子' => ' suǒ zǐ', + '锁子' => ' suǒ zǐ', + '散记' => ' sǎn jì', + '划拉' => ' huá lā', + '这末' => ' zhè me', + '阿明' => ' a míng', + '穗子' => ' suì zǐ', + '这麽' => ' zhè me', + '卜卦' => ' bǔ guà', + '卜甲' => ' bǔ jiǎ', + '阿莲' => ' a lián', + '阿胶' => ' ē jiāo', + '阿盟' => ' a méng', + '博白' => ' bó bái', + '色晕' => ' sè yùn', + '逮捕' => ' dài bǔ', + '杉木' => ' shā mù', + '痧子' => ' shā zǐ', + '三曲' => ' sān qǔ', + '胎发' => ' tāi fà', + '他处' => ' tā chǔ', + '阘懦' => ' tà nuò', + '勾勒' => ' gōu lè', + '化子' => ' huā zi', + '游子' => ' yóu zǐ', + '阇梨' => ' shé lí', + '射的' => ' shè dì', + '折辱' => ' shé rǔ', + '俗乐' => ' sú yuè', + '违拗' => ' wéi ào', + '递解' => ' dì jiè', + '区处' => ' qū chǔ', + '数伏' => ' shǔ fú', + '文蛤' => ' wén gé', + '嗒然' => ' tà rán', + '包袱' => ' bāo fú', + '遗著' => ' yí zhù', + '包扎' => ' bāo zā', + '刨子' => ' bào zǐ', + '避难' => ' bì nàn', + '门子' => ' mén zǐ', + '斗大' => ' dǒu dà', + '阿扁' => ' a biǎn', + '散体' => ' sǎn tǐ', + '卜筮' => ' bǔ shì', + '斗笠' => ' dǒu lì', + '削发' => ' xuē fà', + '部分' => ' bù fèn', + '什物' => ' shí wù', + '勒索' => ' lè suǒ', + '凿子' => ' záo zǐ', + '逻辑' => ' luó ji', + '旄倪' => ' mào ní', + '那是' => ' nà shi', + '那知' => ' nǎ zhī', + '旄期' => ' mào qī', + '旅舍' => ' lǚ shè', + '孕吐' => ' yùn tù', + '是得' => ' shì de', + '肆掠' => ' sì lüě', + '石堤' => ' shí dī', + '都匀' => ' dū yún', + '日头' => ' rì tou', + '识记' => ' zhì jì', + '錾子' => ' zàn zǐ', + '都尉' => ' dū wèi', + '镏子' => ' liù zǐ', + '都市' => ' dū shì', + '铺轨' => ' pū guǐ', + '铺设' => ' pū shè', + '新都' => ' xīn dū', + '都兰' => ' dū lán', + '配子' => ' pèi zǐ', + '铺摊' => ' pū tan', + '铺摆' => ' pū bǎi', + '铺排' => ' pū pái', + '食邑' => ' shí yì', + '配给' => ' pèi jǐ', + '石子' => ' shí zǐ', + '酒吧' => ' jiǔ bā', + '世子' => ' shì zǐ', + '释子' => ' shì zǐ', + '刹那' => ' chà nà', + '剥皮' => ' bāo pí', + '金发' => ' jīn fà', + '哀切' => ' āi qiē', + '劈叉' => ' pǐ chà', + '划破' => ' huá pò', + '昧没' => ' mèi mò', + '黍子' => ' shǔ zǐ', + '竖子' => ' shù zǐ', + '晏子' => ' yàn zǐ', + '普查' => ' pǔ zhā', + '晕乎' => ' yūn hu', + '晕糊' => ' yūn hu', + '力拓' => ' lì tuò', + '切割' => ' qiē gē', + '切勿' => ' qiē wù', + '子音' => ' zǐ yīn', + '都下' => ' dū xià', + '多哇' => ' duō wā', + '咯血' => ' kǎ xiě', + '多子' => ' duō zǐ', + '恶寒' => ' wù hán', + '多得' => ' duō de', + '都试' => ' dū shì', + '铐子' => ' kào zǐ', + '科处' => ' kē chǔ', + '压板' => ' yà bǎn', + '咳血' => ' ké xuè', + '式子' => ' shì zǐ', + '压根' => ' yà gēn', + '客舍' => ' kè shè', + '兜子' => ' dōu zǐ', + '尻子' => ' kāo zǐ', + '斗子' => ' dǒu zi', + '篼子' => ' dōu zǐ', + '坷坎' => ' kē kǎn', + '士子' => ' shì zǐ', + '克尽' => ' kè jìn', + '刻划' => ' kè huá', + '多咱' => ' duō zá', + '靠得' => ' kào de', + '痘子' => ' dòu zǐ', + '来子' => ' lái zǐ', + '得要' => ' de yào', + '老区' => ' lǎo ōu', + '老仆' => ' lǎo pú', + '莱塞' => ' lái sè', + '堤围' => ' dī wéi', + '落儿' => ' lào ér', + '得很' => ' de hěn', + '塌实' => ' tā shi', + '塔刹' => ' tǎ chà', + '赖子' => ' lài zǐ', + '砘子' => ' dùn zǐ', + '老佛' => ' lǎo fó', + '阿房' => ' ē páng', + '斗渠' => ' dǒu qú', + '都头' => ' dū tóu', + '靠泊' => ' kào bó', + '引得' => ' yǐn de', + '引子' => ' yǐn zǐ', + '墩子' => ' dūn zǐ', + '多佛' => ' duō fó', + '看得' => ' kàn de', + '壬子' => ' rén zǐ', + '报子' => ' bào zǐ', + '低徊' => ' dī huí', + '毫子' => ' háo zǐ', + '贵子' => ' guì zǐ', + '脊檩' => ' jǐ lǐn', + '桂子' => ' guì zǐ', + '辊子' => ' gǔn zǐ', + '磙子' => ' gǔn zǐ', + '极尽' => ' jí jìn', + '射干' => ' yè gān', + '急煞' => ' jí shà', + '会子' => ' huì zǐ', + '很子' => ' hěn zǐ', + '妹子' => ' mèi zǐ', + '子爵' => ' zǐ jué', + '安分' => ' ān fèn', + '孽子' => ' niè zǐ', + '学摸' => ' xué mo', + '学子' => ' xué zǐ', + '子群' => ' zǐ qún', + '子民' => ' zǐ mín', + '侯波' => ' hòu bō', + '厚朴' => ' hòu pò', + '季肋' => ' jì lèi', + '姥爷' => ' lǎo ye', + '尉迟' => ' yù chí', + '拂过' => ' bì guò', + '耠子' => ' huō zǐ', + '诘责' => ' jié zé', + '国子' => ' guó zǐ', + '系带' => ' jì dài', + '极处' => ' jí chǔ', + '馃子' => ' guǒ zǐ', + '哈什' => ' hà shí', + '海曲' => ' hǎi qǔ', + '宝坻' => ' bǎo dǐ', + '扞格' => ' hàn gé', + '镬子' => ' huò zǐ', + '豁子' => ' huō zǐ', + '寻死' => ' xín sǐ', + '娄子' => ' lóu zǐ', + '好古' => ' hào gǔ', + '浑似' => ' hún sì', + '喊呀' => ' hǎn yā', + '子代' => ' zǐ dài', + '威吓' => ' wēi hè', + '委靡' => ' wěi mǐ', + '对子' => ' duì zǐ', + '寻的' => ' xún dì', + '妗子' => ' jìn zǐ', + '地煞' => ' dì shà', + '复查' => ' fù zhā', + '露富' => ' lòu fù', + '几微' => ' jī wēi', + '榧子' => ' fěi zǐ', + '干吗' => ' gàn má', + '几至' => ' jī zhì', + '橛子' => ' jué zǐ', + '庶几' => ' shù jī', + '庶子' => ' shù zǐ', + '二舍' => ' èr shè', + '发鬓' => ' fà bìn', + '座子' => ' zuò zǐ', + '倔巴' => ' juè bā', + '飞子' => ' fēi zǐ', + '度假' => ' dù jià', + '庇荫' => ' bì yìn', + '法帖' => ' fǎ tiè', + '发噱' => ' fā xué', + '几近' => ' jī jìn', + '发指' => ' fà zhǐ', + '夥计' => ' huǒ ji', + '蹶子' => ' jué zǐ', + '九曲' => ' jiǔ qǔ', + '分得' => ' fēn de', + '九子' => ' jiǔ zǐ', + '干系' => ' gān xì', + '太仆' => ' tài pú', + '读为' => ' dú wéi', + '厚薄' => ' hòu bó', + '任子' => ' rèn zǐ', + '雹子' => ' báo zǐ', + '体查' => ' tǐ zhā', + '切尼' => ' qiē ní', + '难得' => ' nán de', + '散剂' => ' sǎn jì', + '忍得' => ' rěn de', + '叉子' => ' chā zǐ', + '安处' => ' ān chǔ', + '菲仪' => ' fěi yí', + '幡子' => ' fān zǐ', + '干邑' => ' gān yì', + '大夫' => ' dài fū', + '柜柳' => ' jǔ liǔ', + '菲薄' => ' fěi bó', + '凡子' => ' fán zǐ', + '干与' => ' gān yù', + '舅子' => ' jiù zǐ', + '干戈' => ' gān gē', + '大为' => ' dà wéi', + '金铺' => ' jīn pū', + '佛头' => ' fó tóu', + '癞子' => ' lài zǐ', + '弹牙' => ' tán yá', + '佛界' => ' fó jiè', + '巴斗' => ' bā dǒu', + '杰子' => ' jié zǐ', + '厨子' => ' chú zǐ', + '盔子' => ' kuī zǐ', + '铫子' => ' yáo zǐ', + '弹词' => ' tán cí', + '塞语' => ' sài yǔ', + '塞音' => ' sè yīn', + '弯子' => ' wān zǐ', + '佛国' => ' fó guó', + '胯子' => ' kuà zǐ', + '墨斗' => ' mò dǒu', + '弹子' => ' dàn zǐ', + '弹压' => ' tán yā', + '豆秸' => ' dòu jí', + '压倒' => ' yā dǎo', + '弹劾' => ' tán hé', + '弹拨' => ' tán bō', + '弹力' => ' tán lì', + '影儿' => ' yǐng r', + '佛化' => ' fó huà', + '佛宝' => ' fó bǎo', + '太子' => ' tài zǐ', + '佛座' => ' fó zuò', + '进给' => ' jìn jǐ', + '佛心' => ' fó xīn', + '佛印' => ' fó yìn', + '佛事' => ' fó shì', + '佛珠' => ' fó zhū', + '褯子' => ' jiè zǐ', + '节子' => ' jiē zǐ', + '疖子' => ' jiē zǐ', + '芥子' => ' jiè zǐ', + '街子' => ' jiē zǐ', + '幔子' => ' màn zǐ', + '天儿' => ' tiān r', + '佛人' => ' fó rén', + '佛老' => ' fó lǎo', + '纷沓' => ' fēn tà', + '师傅' => ' shī fū', + '帖子' => ' tiě zǐ', + '大只' => ' dà zhī', + '大难' => ' dà nàn', + '禁曲' => ' jìn qǔ', + '布什' => ' bù shí', + '禁子' => ' jìn zǐ', + '错处' => ' cuò chǔ', + '回应' => ' huí yìng', + '锥子' => ' zhuī zǐ', + '重头' => ' chóng tóu', + '靓仔' => ' liàng zǎi', + '手缝' => ' shǒu féng', + '蒙哄' => ' méng hǒng', + '手卷' => ' shǒu juàn', + '上分' => ' shàng fèn', + '靓妹' => ' liàng mèi', + '上切' => ' shàng qiē', + '升斗' => ' shēng dǒu', + '门框' => ' mén kuàng', + '惩处' => ' chéng chǔ', + '找着' => ' zhǎo zháo', + '丧葬' => ' sāng zàng', + '应点' => ' yìng diǎn', + '长号' => ' cháng hào', + '应酬' => ' yìng chóu', + '投中' => ' tóu zhòng', + '长门' => ' cháng mén', + '音长' => ' yīn cháng', + '长处' => ' cháng chù', + '长眉' => ' cháng méi', + '阮元' => ' ruǎn yuán', + '杓棒' => ' sháo bàng', + '应变' => ' yìng biàn', + '穰穰' => ' rǎng rǎng', + '哄骗' => ' hǒng piàn', + '白相' => ' bái xiàng', + '重获' => ' chóng huò', + '耍横' => ' shuǎ hèng', + '重版' => ' chóng bǎn', + '丧棒' => ' sāng bàng', + '重出' => ' chóng chū', + '绕梁' => ' rǎo liáng', + '少康' => ' shào kāng', + '阆苑' => ' làng yuàn', + '长牌' => ' cháng pái', + '闷声' => ' mēn shēng', + '间苗' => ' jiàn miáo', + '扁舟' => ' piān zhōu', + '间断' => ' jiàn duàn', + '少小' => ' shào xiǎo', + '烧着' => ' shāo zháo', + '闲空' => ' xián kòng', + '戴上' => ' dài shang', + '长排' => ' cháng pái', + '扇动' => ' shān dòng', + '沈朴' => ' shěn piáo', + '长毛' => ' cháng máo', + '切向' => ' qiē xiàng', + '三率' => ' sān shuài', + '长直' => ' cháng zhí', + '扮相' => ' bàn xiàng', + '长醉' => ' cháng zuì', + '朝朝' => ' zhāo zhāo', + '雕琢' => ' diāo zhuó', + '南长' => ' nán cháng', + '双子' => ' shuāng zǐ', + '长随' => ' cháng suí', + '长夏' => ' cháng xià', + '降妖' => ' xiáng yāo', + '手钻' => ' shǒu zuàn', + '长休' => ' cháng xiū', + '三乘' => ' sān shèng', + '长心' => ' cháng xīn', + '长信' => ' cháng xìn', + '长音' => ' cháng yīn', + '长吟' => ' cháng yín', + '长云' => ' cháng yún', + '盛载' => ' shèng zǎi', + '盛满' => ' chéng mǎn', + '效应' => ' xiào yìng', + '长头' => ' cháng tóu', + '青藏' => ' qīng zàng', + '长舌' => ' cháng shé', + '长逝' => ' cháng shì', + '长至' => ' cháng zhì', + '应诏' => ' yìng zhào', + '重写' => ' chóng xiě', + '长袍' => ' cháng páo', + '长袖' => ' cháng xiù', + '舍长' => ' shè cháng', + '重来' => ' chóng lái', + '长靴' => ' cháng xuē', + '长队' => ' cháng duì', + '摆晃' => ' bǎi huàng', + '应诊' => ' yìng zhěn', + '重数' => ' chóng shù', + '重拍' => ' chóng pāi', + '深更' => ' shēn gēng', + '成分' => ' chéng fèn', + '长跑' => ' cháng pǎo', + '挑动' => ' tiǎo dòng', + '长谈' => ' cháng tán', + '长诗' => ' cháng shī', + '长裙' => ' cháng qún', + '成为' => ' chéng wéi', + '吵吵' => ' chāo chao', + '拙朴' => ' zhuō piáo', + '散光' => ' sǎn guāng', + '刁横' => ' diāo hèng', + '调准' => ' tiáo zhǔn', + '摒挡' => ' bìng dàng', + '调调' => ' tiáo diào', + '调档' => ' tiáo dàng', + '挑灯' => ' tiǎo dēng', + '调料' => ' tiáo liào', + '调弄' => ' tiáo nòng', + '调教' => ' tiáo jiào', + '调挡' => ' tiáo dǎng', + '调卷' => ' diào juàn', + '冰凝' => ' bīng níng', + '棚圈' => ' péng juàn', + '调控' => ' tiáo kòng', + '喷香' => ' pèn xiāng', + '挑明' => ' tiǎo míng', + '援藏' => ' yuán zàng', + '卖相' => ' mài xiàng', + '转差' => ' zhuǎn chā', + '转台' => ' zhuàn tái', + '换行' => ' huàn háng', + '更换' => ' gēng huàn', + '调情' => ' tiáo qíng', + '调笑' => ' tiáo xiào', + '轮转' => ' lún zhuàn', + '变更' => ' biàn gēng', + '漂漂' => ' piāo piāo', + '碘酊' => ' diǎn dǐng', + '背筐' => ' bēi kuāng', + '贫相' => ' pín xiàng', + '琅孉' => ' láng huān', + '财相' => ' cái xiàng', + '调弦' => ' tiáo xián', + '振兴' => ' zhèn xīng', + '命名' => ' mìng míng', + '曾参' => ' zēng shēn', + '并州' => ' bīng zhōu', + '兵差' => ' bīng chāi', + '调焦' => ' tiáo jiāo', + '调停' => ' tiáo tíng', + '典当' => ' diǎn dàng', + '顶杠' => ' dǐng gàng', + '定更' => ' dìng gēng', + '曾巩' => ' zēng gǒng', + '挑战' => ' tiǎo zhàn', + '鼎兴' => ' dǐng xīng', + '挑弄' => ' tiǎo nòng', + '转位' => ' zhuàn wèi', + '轮种' => ' lún zhòng', + '百中' => ' bǎi zhòng', + '平巷' => ' píng hàng', + '天应' => ' tiān yìng', + '掉色' => ' diào shǎi', + '天监' => ' tiān jiàn', + '刨光' => ' bào guāng', + '跳行' => ' tiào háng', + '走相' => ' zǒu xiàng', + '赚头' => ' zhuàn tou', + '账载' => ' zhàng zǎi', + '评卷' => ' píng juàn', + '楞楞' => ' lèng lèng', + '分相' => ' fēn xiàng', + '分量' => ' fèn liàng', + '接种' => ' jiē zhòng', + '白镪' => ' bái qiǎng', + '坦率' => ' tǎn shuài', + '更深' => ' gēng shēn', + '切成' => ' qiē chéng', + '挣脱' => ' zhèng tuō', + '挣扎' => ' zhēng zhá', + '切中' => ' qiè zhòng', + '轩槛' => ' xuān jiàn', + '哄劝' => ' hǒng quàn', + '招供' => ' zhāo gòng', + '插上' => ' chā shang', + '转载' => ' zhuǎn zǎi', + '重奏' => ' chóng zòu', + '镗孔' => ' táng kǒng', + '糖色' => ' táng shǎi', + '蛣蜣' => ' jié qiāng', + '转悠' => ' zhuàn yōu', + '转门' => ' zhuàn mén', + '转游' => ' zhuàn you', + '更动' => ' gēng dòng', + '转轮' => ' zhuàn lún', + '拖长' => ' tuō cháng', + '蹭蹬' => ' cèng dèng', + '更名' => ' gēng míng', + '转文' => ' zhuǎi wén', + '倒想' => ' dǎo xiǎng', + '倒箱' => ' dǎo xiāng', + '揣度' => ' chuǎi duó', + '转纽' => ' zhuàn nǐu', + '转筋' => ' zhuàn jīn', + '农行' => ' nóng háng', + '败将' => ' bài jiàng', + '叨光' => ' tāo guāng', + '长蛇' => ' cháng shé', + '电钻' => ' diàn zuàn', + '影片' => ' yǐng piān', + '长干' => ' cháng gàn', + '钟乐' => ' zhōng yuè', + '劲风' => ' jìng fēng', + '啜茗' => ' chuò míng', + '长褂' => ' cháng guà', + '旋工' => ' xuàn gōng', + '飞转' => ' fēi zhuàn', + '折衷' => ' shé zhōng', + '哮鸣' => ' xiào míng', + '劲挺' => ' jìng tǐng', + '撩动' => ' liáo dòng', + '长跪' => ' cháng guì', + '史乘' => ' shǐ shèng', + '劲峭' => ' jìng qiào', + '撬杠' => ' qiào gàng', + '应召' => ' yìng zhào', + '长恨' => ' cháng hèn', + '长尾' => ' cháng wěi', + '长存' => ' cháng cún', + '长多' => ' cháng duō', + '懂行' => ' dǒng háng', + '长叹' => ' cháng tàn', + '春兴' => ' chūn xīng', + '长岛' => ' cháng dǎo', + '长假' => ' cháng jià', + '长白' => ' cháng bái', + '长杰' => ' cháng jié', + '省方' => ' xǐng fāng', + '长街' => ' cháng jiē', + '长海' => ' cháng hǎi', + '长滨' => ' cháng bīn', + '单县' => ' shàn xiàn', + '长矛' => ' cháng máo', + '应用' => ' yìng yòng', + '参茸' => ' shēn róng', + '长男' => ' cháng nán', + '生角' => ' shēng jué', + '颈椎' => ' jǐng zhuī', + '长流' => ' cháng liú', + '投降' => ' tóu xiáng', + '长班' => ' cháng bān', + '棽棽' => ' chēn chēn', + '长林' => ' cháng lín', + '应景' => ' yìng jǐng', + '长列' => ' cháng liè', + '长烟' => ' cháng yān', + '受禅' => ' shòu shàn', + '钻井' => ' zuàn jǐng', + '折秤' => ' shé chèng', + '身着' => ' shēn zhuó', + '桁杨' => ' háng yáng', + '校监' => ' xiào jiàn', + '悍将' => ' hàn jiàng', + '校订' => ' jiào dìng', + '缥囊' => ' piǎo náng', + '纤手' => ' qiàn shǒu', + '猜中' => ' cāi zhòng', + '宽甸' => ' kuān diàn', + '率然' => ' shuài rán', + '绗缝' => ' háng féng', + '粘着' => ' nián zhuó', + '差商' => ' chā shāng', + '射中' => ' shè zhòng', + '奉还' => ' fèng huán', + '应典' => ' yìng diǎn', + '粘胶' => ' nián jiāo', + '交还' => ' jiāo huán', + '应供' => ' yìng gòng', + '粘粘' => ' nián nián', + '粘稠' => ' nián chóu', + '杆秤' => ' gǎn chèng', + '粘性' => ' nián xìng', + '校准' => ' jiào zhǔn', + '种菜' => ' zhòng cài', + '风钻' => ' fēng zuàn', + '份量' => ' fèn liang', + '长活' => ' cháng huó', + '长话' => ' cháng huà', + '慢长' => ' màn cháng', + '旋风' => ' xuàn fēng', + '长久' => ' cháng jiǔ', + '共工' => ' gòng gōng', + '戎行' => ' róng háng', + '杠杠' => ' gàng gàng', + '伄儅' => ' diào dāng', + '缝缀' => ' féng zhuì', + '缥渺' => ' piǎo miǎo', + '缅甸' => ' miǎn diàn', + '正旦' => ' zhēng dàn', + '干城' => ' gān chéng', + '率直' => ' shuài zhí', + '网杓' => ' wǎng sháo', + '正切' => ' zhèng qiē', + '经卷' => ' jīng juàn', + '栽种' => ' zāi zhòng', + '甚浓' => ' shèn nóng', + '正月' => ' zhēng yuè', + '长幼' => ' cháng yòu', + '身著' => ' shēn zhuó', + '露相' => ' lòu xiàng', + '薯莨' => ' shǔ liáng', + '重述' => ' chóng shù', + '重迭' => ' chóng dié', + '骗供' => ' piàn gòng', + '重蹈' => ' chóng dǎo', + '骄横' => ' jiāo hèng', + '重制' => ' chóng zhì', + '惊醒' => ' jīng xǐng', + '长材' => ' cháng cái', + '重返' => ' chóng fǎn', + '量杯' => ' liáng bēi', + '长车' => ' cháng chē', + '长刀' => ' cháng dāo', + '世相' => ' shì xiàng', + '加长' => ' jiā cháng', + '铺床' => ' pū chuáng', + '明了' => ' míng liǎo', + '攒动' => ' cuán dòng', + '撩乱' => ' liáo luàn', + '馕嗓' => ' nǎng sǎng', + '香干' => ' xiāng gān', + '加上' => ' jiā shang', + '掸邦' => ' shàn bāng', + '重造' => ' chóng zào', + '想头' => ' xiǎng tou', + '扇风' => ' shān fēng', + '城阙' => ' chéng què', + '称手' => ' chèn shǒu', + '尨茸' => ' méng róng', + '趁空' => ' chèn kòng', + '丧乱' => ' sāng luàn', + '卷轴' => ' juàn zhóu', + '称身' => ' chèn shēn', + '晨兴' => ' chén xīng', + '趁兴' => ' chèn xīng', + '茸茸' => ' róng róng', + '清供' => ' qīng gòng', + '称愿' => ' chèn yuàn', + '钐镰' => ' shàn lián', + '卷宗' => ' juàn zōng', + '善卷' => ' shàn juàn', + '盛饭' => ' chéng fàn', + '山岗' => ' shān gāng', + '重婚' => ' chóng hūn', + '长石' => ' cháng shí', + '单相' => ' dān xiàng', + '重开' => ' chóng kāi', + '馕糠' => ' nǎng kāng', + '量规' => ' liáng guī', + '长棍' => ' cháng gùn', + '重演' => ' chóng yǎn', + '重查' => ' chóng chá', + '脏乱' => ' zāng luàn', + '晃悠' => ' huàng yōu', + '重温' => ' chóng wēn', + '嚷嚷' => ' rāng rɑng', + '划伤' => ' huá shāng', + '脏水' => ' zāng shuǐ', + '剿说' => ' chāo shuō', + '重楼' => ' chóng lóu', + '顺应' => ' shùn yìng', + '悠长' => ' yōu cháng', + '劲吹' => ' jìng chuī', + '应手' => ' yìng shǒu', + '应战' => ' yìng zhàn', + '长治' => ' cháng zhì', + '长沙' => ' cháng shā', + '应从' => ' yìng cóng', + '长俊' => ' cháng jùn', + '求降' => ' qiú xiáng', + '深省' => ' shēn xǐng', + '长泰' => ' cháng tài', + '重犯' => ' chóng fàn', + '长坂' => ' cháng bǎn', + '隆兴' => ' lóng xīng', + '邻长' => ' lín cháng', + '寸长' => ' cùn cháng', + '龙兴' => ' lóng xīng', + '儱侗' => ' lǒng tǒng', + '重叠' => ' chóng dié', + '重瓣' => ' chóng bàn', + '脏病' => ' zāng bìng', + '重新' => ' chóng xīn', + '晕船' => ' yùn chuán', + '重文' => ' chóng wén', + '重担' => ' zhòng dàn', + '灵应' => ' líng yìng', + '重插' => ' chóng chā', + '晕场' => ' yùn chǎng', + '脏脏' => ' zāng zāng', + '重拾' => ' chóng shí', + '重弹' => ' chóng tán', + '重孙' => ' chóng sūn', + '召陵' => ' shào líng', + '长才' => ' cháng cái', + '晾干' => ' liàng gān', + '重构' => ' chóng gòu', + '点着' => ' diǎn zháo', + '铜钿' => ' tóng tián', + '嚼用' => ' jiáo yòng', + '卷柜' => ' juàn guì', + '两得' => ' liǎng de', + '消褪' => ' xiāo tùn', + '校书' => ' jiào shū', + '卷包' => ' juàn bāo', + '小舍' => ' xiǎo shè', + '卷丹' => ' juàn dān', + '圈肥' => ' juàn féi', + '圈舍' => ' juàn shè', + '划艇' => ' huá tǐng', + '随兴' => ' suí xīng', + '连杆' => ' lián gǎn', + '划算' => ' huá suàn', + '划拳' => ' huá quán', + '索还' => ' suǒ huán', + '小侯' => ' xiǎo hòu', + '销号' => ' xiāo hào', + '小斗' => ' xiǎo dǒu', + '小尽' => ' xiǎo jìn', + '丹参' => ' dān shēn', + '奔丧' => ' bēn sāng', + '倒换' => ' dǎo huàn', + '颉颃' => ' xié háng', + '执著' => ' zhí zhuó', + '相如' => ' xiàng rú', + '初更' => ' chū gēng', + '两都' => ' liǎng dū', + '像似' => ' xiàng sì', + '卷缩' => ' juàn suō', + '台钻' => ' tái zuàn', + '卷头' => ' juàn tóu', + '卷尾' => ' juàn wěi', + '朘削' => ' juān xuē', + '切点' => ' qiē diǎn', + '切面' => ' qiē miàn', + '相马' => ' xiàng mǎ', + '太甚' => ' tài shèn', + '降魔' => ' xiáng mó', + '切变' => ' qiē biàn', + '相里' => ' xiàng lǐ', + '相和' => ' xiāng hè', + '相得' => ' xiāng de', + '倒腾' => ' dǎo téng', + '切线' => ' qiē xiàn', + '在行' => ' zài háng', + '切痛' => ' qiē tòng', + '曲张' => ' qǔ zhāng', + '参宿' => ' shēn xìu', + '前头' => ' qián tou', + '口供' => ' kǒu gòng', + '女将' => ' nǚ jiàng', + '中得' => ' zhōng de', + '著实' => ' zhuó shí', + '抢地' => ' qiāng dì', + '划行' => ' huá xíng', + '花朝' => ' huā zhāo', + '中意' => ' zhòng yì', + '三藏' => ' sān zàng', + '乾造' => ' qián zào', + '原处' => ' yuán chǔ', + '群氓' => ' qún méng', + '朝霞' => ' zhāo xiá', + '三通' => ' sān tòng', + '钻杆' => ' zuàn gǎn', + '黄子' => ' huáng zǐ', + '弄口' => ' lòng kǒu', + '受难' => ' shòu nàn', + '中子' => ' zhōng zǐ', + '染坊' => ' rǎn fáng', + '篇什' => ' piān shí', + '原著' => ' yuán zhù', + '划水' => ' huá shuǐ', + '属望' => ' zhǔ wàng', + '昭著' => ' zhāo zhù', + '折行' => ' shé xíng', + '周处' => ' zhōu chǔ', + '炔烃' => ' quē tīng', + '牛鞅' => ' niú yàng', + '并处' => ' bìng chǔ', + '评弹' => ' píng tán', + '折干' => ' shé qián', + '内省' => ' nèi xǐng', + '确当' => ' què dàng', + '朝云' => ' zhāo yún', + '仔兽' => ' zǎi shòu', + '受累' => ' shòu lěi', + '牛圈' => ' niú juàn', + '拧紧' => ' nǐng jǐn', + '吹干' => ' chuī gān', + '折减' => ' shé jiǎn', + '还丹' => ' huán dān', + '三更' => ' sān gēng', + '折受' => ' shé shòu', + '子姜' => ' zǐ jiāng', + '哄瞒' => ' hǒng mán', + '妥当' => ' tuǒ dàng', + '切片' => ' qiē piàn', + '大王' => ' dài wáng', + '曲种' => ' qǔ zhǒng', + '拓边' => ' tuò biān', + '铜臭' => ' tóng xiù', + '公假' => ' gōng jià', + '公斗' => ' gōng dǒu', + '公石' => ' gōng dàn', + '偷空' => ' tōu kòng', + '冗散' => ' rǒng sǎn', + '筐子' => ' kuāng zǐ', + '拓宽' => ' tuò kuān', + '款识' => ' kuǎn zhì', + '外应' => ' wài yìng', + '空载' => ' kōng zǎi', + '调休' => ' tiáo xiū', + '肯綮' => ' kěn qìng', + '同好' => ' tóng hào', + '调治' => ' tiáo zhì', + '充塞' => ' chōng sè', + '兆头' => ' zhào tou', + '为甚' => ' wéi shèn', + '光子' => ' guāng zǐ', + '出差' => ' chū chāi', + '为善' => ' wéi shàn', + '公仔' => ' gōng zǎi', + '内哄' => ' nèi hòng', + '冷轧' => ' lěng zhá', + '执着' => ' zhí zhuó', + '坤甸' => ' kūn diàn', + '肋条' => ' lèi tiáo', + '螣蛇' => ' téng shé', + '假条' => ' jià tiáo', + '切块' => ' qiē kuài', + '乐工' => ' yuè gōng', + '累年' => ' lěi nián', + '偏差' => ' piān chā', + '埋怨' => ' mán yuàn', + '切削' => ' qiē xiāo', + '内行' => ' nèi háng', + '天阙' => ' tiān què', + '开兴' => ' kāi xīng', + '添头' => ' tiān tou', + '累卵' => ' léi luǎn', + '瞎蒙' => ' xiā mēng', + '为限' => ' wéi xiàn', + '冠军' => ' guàn jūn', + '王舍' => ' wáng shè', + '阔少' => ' kuò shào', + '内蒙' => ' nèi měng', + '出丧' => ' chū sāng', + '来还' => ' lái huán', + '削球' => ' xiāo qiú', + '兴修' => ' xīng xiū', + '卷柏' => ' juàn bǎi', + '倒噍' => ' dǎo jiào', + '倒手' => ' dǎo shǒu', + '兴家' => ' xīng jiā', + '救应' => ' jiù yìng', + '供认' => ' gòng rèn', + '兴运' => ' xīng yùn', + '便人' => ' pián rén', + '剪切' => ' jiǎn qiē', + '型芯' => ' xíng xìn', + '倒扁' => ' dǎo biǎn', + '率意' => ' shuài yì', + '剥啄' => ' bāo zhuó', + '栓子' => ' shuān zǐ', + '便难' => ' biàn nàn', + '前燕' => ' qián yān', + '回佣' => ' huí yòng', + '前咽' => ' qián yān', + '兴叹' => ' xīng tàn', + '税卡' => ' shuì qiǎ', + '信差' => ' xìn chāi', + '因应' => ' yīn yìng', + '刨冰' => ' bào bīng', + '铁杠' => ' tiě gàng', + '里长' => ' lǐ cháng', + '萎蔫' => ' wěi niān', + '亭侯' => ' tíng hòu', + '为命' => ' wéi mìng', + '为名' => ' wéi míng', + '课长' => ' kè cháng', + '同处' => ' tóng chǔ', + '为患' => ' wéi huàn', + '为情' => ' wéi qíng', + '精舍' => ' jīng shè', + '霰弹' => ' xiàn dàn', + '倒弄' => ' dǎo nòng', + '九钻' => ' jiǔ zuàn', + '杏干' => ' xìng gān', + '梁子' => ' liáng zǐ', + '兴废' => ' xīng fèi', + '倒仓' => ' dǎo cāng', + '大将' => ' dà jiàng', + '刺中' => ' cì zhòng', + '行处' => ' xíng chǔ', + '回还' => ' huí huán', + '倒嚼' => ' dǎo jiào', + '子将' => ' zǐ jiāng', + '反间' => ' fǎn jiàn', + '调羹' => ' tiáo gēng', + '重修' => ' chóng xiū', + '当行' => ' dāng háng', + '刚劲' => ' gāng jìng', + '刷卷' => ' shuā juàn', + '同行' => ' tóng háng', + '重围' => ' chóng wéi', + '摇晃' => ' yáo huàng', + '重回' => ' chóng huí', + '重又' => ' chóng yòu', + '重印' => ' chóng yìn', + '吊杠' => ' diào gàng', + '乾龙' => ' qián lóng', + '衰萎' => ' shuāi wěi', + '太冲' => ' tài chòng', + '追还' => ' zhuī huán', + '吊卷' => ' diào juàn', + '俏销' => ' qiào xiāo', + '重九' => ' chóng jiǔ', + '党参' => ' dǎng shēn', + '靓白' => ' liàng bái', + '强人' => ' qiǎng rén', + '性行' => ' xìng xíng', + '通红' => ' tòng hóng', + '划船' => ' huá chuán', + '两肋' => ' liǎng lèi', + '中计' => ' zhòng jì', + '级长' => ' jí cháng', + '中牟' => ' zhōng mù', + '浑朴' => ' hún piáo', + '皮相' => ' pí xiàng', + '画片' => ' huà piān', + '中脊' => ' zhōng jǐ', + '豁朗' => ' huò lǎng', + '切手' => ' qiē shǒu', + '啁啾' => ' zhōu jiū', + '盅子' => ' zhōng zǐ', + '拓荒' => ' tuò huāng', + '儒将' => ' rú jiàng', + '中举' => ' zhòng jǔ', + '竹行' => ' zhú háng', + '裨将' => ' pí jiàng', + '作践' => ' zuó jiàn', + '惬当' => ' qiè dàng', + '昏蒙' => ' hūn mēng', + '划桨' => ' huá jiǎng', + '台长' => ' tái cháng', + '乾明' => ' qián míng', + '单姓' => ' shàn xìng', + '膻中' => ' dàn zhōng', + '娘子' => ' niáng zǐ', + '轰隆' => ' hōng lōng', + '运转' => ' yùn zhuàn', + '别传' => ' bié zhuàn', + '难兄' => ' nàn xiōng', + '了断' => ' liǎo duàn', + '道长' => ' dào cháng', + '削尖' => ' xiāo jiān', + '男相' => ' nán xiàng', + '还手' => ' huán shǒu', + '占星' => ' zhān xīng', + '识相' => ' shí xiàng', + '吃相' => ' chī xiàng', + '便了' => ' biàn liǎo', + '听差' => ' tīng chāi', + '咸兴' => ' xián xīng', + '往还' => ' wǎng huán', + '诸相' => ' zhū xiàng', + '诸将' => ' zhū jiàng', + '调养' => ' tiáo yǎng', + '凝冰' => ' níng bīng', + '彭彭' => ' bāng bāng', + '彷徉' => ' páng yáng', + '摔倒' => ' shuāi dǎo', + '内传' => ' nèi zhuàn', + '还债' => ' huán zhài', + '当差' => ' dāng chāi', + '强切' => ' qiáng qiē', + '还原' => ' huán yuán', + '曹长' => ' cáo cháng', + '刨程' => ' bào chéng', + '还清' => ' huán qīng', + '钌铞' => ' liào diào', + '还愿' => ' huán yuàn', + '掺水' => ' chān shuǐ', + '当票' => ' dàng piào', + '强留' => ' qiǎng liú', + '运将' => ' yùn jiàng', + '摊场' => ' tān cháng', + '强颜' => ' qiǎng yán', + '黑框' => ' hēi kuàng', + '浅浅' => ' jiān jiān', + '乾乾' => ' qián qián', + '连翘' => ' lián qiáo', + '列传' => ' liè zhuàn', + '乾元' => ' qián yuán', + '酬应' => ' chóu yìng', + '酩酊' => ' mǐng dǐng', + '劈账' => ' pǐ zhàng', + '绘卷' => ' huì juàn', + '黄柏' => ' huáng bò', + '颀长' => ' qí cháng', + '曲中' => ' qǔ zhōng', + '清隽' => ' qīng jùn', + '世行' => ' shì háng', + '还家' => ' huán jiā', + '受尽' => ' shòu jìn', + '木强' => ' mù jiàng', + '情切' => ' qíng qiē', + '千载' => ' qiān zǎi', + '能为' => ' néng wéi', + '字长' => ' zì cháng', + '商贾' => ' shāng gǔ', + '清切' => ' qīng qiē', + '受到' => ' shòu dào', + '只缘' => ' zhī yuán', + '轻载' => ' qīng zǎi', + '参校' => ' cān jiào', + '激将' => ' jī jiàng', + '正脊' => ' zhèng jǐ', + '子城' => ' zǐ chéng', + '只手' => ' zhī shǒu', + '黄发' => ' huáng fà', + '商都' => ' shāng dū', + '内应' => ' nèi yìng', + '子长' => ' zǐ cháng', + '曲梁' => ' qǔ liáng', + '吊斗' => ' diào dǒu', + '反省' => ' fǎn xǐng', + '参薯' => ' shēn shǔ', + '始兴' => ' shǐ xīng', + '乞降' => ' qǐ xiáng', + '只从' => ' zhī cóng', + '值当' => ' zhí dàng', + '遒劲' => ' qiú jìng', + '唱曲' => ' chàng qǔ', + '名角' => ' míng jué', + '反应' => ' fǎn yìng', + '指缝' => ' zhǐ féng', + '只见' => ' zhī jiàn', + '名著' => ' míng zhù', + '还珠' => ' huán zhū', + '乾嘉' => ' qián jiā', + '唱喏' => ' chàng rě', + '唱和' => ' chàng hè', + '名为' => ' míng wéi', + '准头' => ' zhǔn tou', + '名帖' => ' míng tiě', + '千石' => ' qiān dàn', + '乾道' => ' qián dào', + '上个' => ' shàng ge', + '獐子' => ' zhāng zǐ', + '难侨' => ' nàn qiáo', + '入相' => ' rù xiàng', + '啜饮' => ' chuò yǐn', + '软和' => ' ruǎn huo', + '咳呛' => ' ké qiàng', + '掌子' => ' zhǎng zǐ', + '画供' => ' huà gòng', + '礃子' => ' zhǎng zǐ', + '哨卡' => ' shào qiǎ', + '障子' => ' zhàng zǐ', + '问卷' => ' wèn juàn', + '作甚' => ' zuò shèn', + '和弄' => ' huò nòng', + '劈成' => ' pǐ chéng', + '妄为' => ' wàng wéi', + '咆哮' => ' páo xiào', + '钻台' => ' zuàn tái', + '猪圈' => ' zhū juàn', + '系绳' => ' jì shéng', + '钻饰' => ' zuàn shì', + '上去' => ' shǎng qù', + '作弄' => ' zuō nòng', + '火燎' => ' huǒ liǎo', + '钻修' => ' zuàn xiū', + '抨弹' => ' pēng tán', + '中魔' => ' zhòng mó', + '钻凿' => ' zuàn záo', + '钻穴' => ' zuàn xué', + '竹杠' => ' zhú gàng', + '衷曲' => ' zhōng qǔ', + '杖子' => ' zhàng zǐ', + '卵泡' => ' luǎn pāo', + '俏头' => ' qiào tou', + '软肋' => ' ruǎn lèi', + '卷帙' => ' juàn zhì', + '柞绸' => ' zuò chóu', + '弱冠' => ' ruò guàn', + '长机' => ' cháng jī', + '切当' => ' qiē dāng', + '和面' => ' huó miàn', + '幛子' => ' zhàng zǐ', + '棚舍' => ' péng shè', + '南甸' => ' nán diàn', + '叩应' => ' kòu yìng', + '切用' => ' qiē yòng', + '中毒' => ' zhòng dú', + '粘缠' => ' nián chán', + '精当' => ' jīng dàng', + '切换' => ' qiē huàn', + '长籼' => ' cháng xiān', + '少成' => ' shào chéng', + '商参' => ' shāng shēn', + '种田' => ' zhòng tián', + '长顺' => ' cháng shùn', + '应承' => ' yìng chéng', + '长眠' => ' cháng mián', + '粘虫' => ' nián chóng', + '长短' => ' cháng duǎn', + '长篇' => ' cháng piān', + '长线' => ' cháng xiàn', + '少长' => ' shào zhǎng', + '长兴' => ' cháng xīng', + '长龙' => ' cháng lóng', + '长虹' => ' cháng hóng', + '长衫' => ' cháng shān', + '长丰' => ' cháng fēng', + '长远' => ' cháng yuǎn', + '长钉' => ' cháng dìng', + '粮行' => ' liáng háng', + '真相' => ' zhēn xiàng', + '少相' => ' shào xiāng', + '闲晃' => ' xián huàng', + '战将' => ' zhàn jiàng', + '转圈' => ' zhuàn quān', + '全长' => ' quán cháng', + '转行' => ' zhuǎn háng', + '调光' => ' tiáo guāng', + '较长' => ' jiào cháng', + '更正' => ' gēng zhèng', + '轻率' => ' qīng shuài', + '纤长' => ' xiān cháng', + '仙长' => ' xiān cháng', + '转动' => ' zhuàn dòng', + '更张' => ' gēng zhāng', + '重阳' => ' chóng yáng', + '倘佯' => ' cháng yáng', + '辗转' => ' zhǎn zhuǎn', + '偏将' => ' piān jiàng', + '天相' => ' tiān xiàng', + '更生' => ' gēng shēng', + '天将' => ' tiān jiàng', + '身长' => ' shēn cháng', + '藏象' => ' zàng xiàng', + '相间' => ' xiāng jiàn', + '胸椎' => ' xiōng zhuī', + '真率' => ' zhēn shuài', + '散装' => ' sǎn zhuāng', + '调整' => ' tiáo zhěng', + '统率' => ' tǒng shuài', + '长条' => ' cháng tiáo', + '经传' => ' jīng zhuàn', + '长拳' => ' cháng quán', + '长荣' => ' cháng róng', + '长汀' => ' cháng tīng', + '终了' => ' zhōng liǎo', + '长清' => ' cháng qīng', + '长漂' => ' cháng piāo', + '长片' => ' cháng piàn', + '勉强' => ' miǎn qiǎng', + '长春' => ' cháng chūn', + '长廊' => ' cháng láng', + '伸长' => ' shēn cháng', + '长凳' => ' cháng dèng', + '长垣' => ' cháng yuán', + '长庚' => ' cháng gēng', + '长寿' => ' cháng shòu', + '绷簧' => ' bēng huáng', + '长宁' => ' cháng níng', + '长岭' => ' cháng lǐng', + '长平' => ' cháng píng', + '长柄' => ' cháng bǐng', + '长效' => ' cháng xiào', + '院长' => ' yuàn cháng', + '镜框' => ' jìng kuàng', + '睡相' => ' shuì xiàng', + '干爽' => ' gān shuǎng', + '山长' => ' shān cháng', + '晒场' => ' shài cháng', + '重逢' => ' chóng féng', + '亭长' => ' tíng cháng', + '耕种' => ' gēng zhòng', + '镇长' => ' zhèn cháng', + '校场' => ' jiào chǎng', + '重霄' => ' chóng xiāo', + '校正' => ' jiào zhèng', + '星相' => ' xīng xiàng', + '量瓶' => ' liáng píng', + '量筒' => ' liáng tǒng', + '扬长' => ' yáng cháng', + '扬场' => ' yáng cháng', + '量身' => ' liáng shēn', + '收降' => ' shōu xiáng', + '手长' => ' shǒu cháng', + '量表' => ' liáng biǎo', + '参商' => ' shēn shāng', + '王长' => ' wáng cháng', + '冗长' => ' rǒng cháng', + '长空' => ' cháng kōng', + '相面' => ' xiàng miàn', + '受降' => ' shòu xiáng', + '猛将' => ' měng jiàng', + '率先' => ' shuài xiān', + '饼铛' => ' bǐng chēng', + '卿相' => ' qīng xiàng', + '请降' => ' qǐng xiáng', + '率领' => ' shuài lǐng', + '率真' => ' shuài zhēn', + '正着' => ' zhèng zháo', + '边框' => ' biān kuàng', + '牵强' => ' qiān qiǎng', + '边长' => ' biān cháng', + '芒种' => ' máng zhòng', + '色钟' => ' shǎi zhōng', + '说项' => ' shuì xiàng', + '色盅' => ' shǎi zhōng', + '前传' => ' qián zhuàn', + '丑相' => ' chǒu xiàng', + '还乡' => ' huán xiāng', + '着凉' => ' zháo liáng', + '着慌' => ' zháo huāng', + '首相' => ' shǒu xiàng', + '准将' => ' zhǔn jiàng', + '小将' => ' xiǎo jiàng', + '黄漂' => ' huáng piāo', + '千乘' => ' qiān shèng', + '点将' => ' diǎn jiàng', + '纤绳' => ' qiàn shéng', + '抢风' => ' qiāng fēng', + '黄兴' => ' huáng xīng', + '强笑' => ' qiǎng xiào', + '照相' => ' zhào xiàng', + '戗面' => ' qiàng miàn', + '上供' => ' shàng gòng', + '响应' => ' xiǎng yìng', + '水相' => ' shuǐ xiàng', + '涨红' => ' zhàng hóng', + '清长' => ' qīng cháng', + '擅长' => ' shàn cháng', + '生还' => ' shēng huán', + '挣钱' => ' zhèng qián', + '挣命' => ' zhèng mìng', + '评传' => ' píng zhuàn', + '挣断' => ' zhèng duàn', + '正朔' => ' zhēng shuò', + '当成' => ' dàng chéng', + '着想' => ' zhuó xiǎng', + '骁将' => ' xiāo jiàng', + '公转' => ' gōng zhuàn', + '通长' => ' tōng cháng', + '雄劲' => ' xióng jìng', + '重样' => ' chóng yàng', + '兴城' => ' xīng chéng', + '创口' => ' chuāng kǒu', + '重映' => ' chóng yìng', + '供称' => ' gòng chēng', + '降龙' => ' xiáng lóng', + '着重' => ' zhuó zhòng', + '表率' => ' biǎo shuài', + '衡量' => ' héng liáng', + '凶横' => ' xiōng hèng', + '行长' => ' háng zhǎng', + '挑中' => ' tiāo zhòng', + '行商' => ' háng shāng', + '变相' => ' biàn xiàng', + '元长' => ' yuán cháng', + '偿还' => ' cháng huán', + '贤相' => ' xián xiàng', + '赚哄' => ' zhuàn hǒng', + '贯串' => ' guàn chuàn', + '诚朴' => ' chéng piáo', + '重庆' => ' chóng qìng', + '重影' => ' chóng yǐng', + '还账' => ' huán zhàng', + '晃动' => ' huàng dòng', + '连长' => ' lián cháng', + '选中' => ' xuǎn zhòng', + '刨床' => ' bào chuáng', + '兴昌' => ' xīng chāng', + '箱笼' => ' xiāng lǒng', + '率性' => ' shuài xìng', + '兴衰' => ' xīng shuāi', + '悬揣' => ' xuán chuǎi', + '重洋' => ' chóng yáng', + '脸相' => ' liǎn xiàng', + '重建' => ' chóng jiàn', + '重现' => ' chóng xiàn', + '膀胱' => ' páng guāng', + '晃荡' => ' huàng dàng', + '重申' => ' chóng shēn', + '重算' => ' chóng suàn', + '重编' => ' chóng biān', + '重访' => ' chóng fǎng', + '重评' => ' chóng píng', + '兴盛' => ' xīng shèng', + '重审' => ' chóng shěn', + '长年' => ' cháng nián', + '绵长' => ' mián cháng', + '上当' => ' shàng dàng', + '相中' => ' xiāng zhòng', + '长成' => ' cháng chéng', + '长枪' => ' cháng qiāng', + '重整' => ' chóng zhěng', + '将将' => ' qiāng qiāng', + '穿上' => ' chuān shang', + '将相' => ' jiàng xiàng', + '倡狂' => ' chāng kuáng', + '着装' => ' zhuó zhuāng', + '相长' => ' xiāng cháng', + '着床' => ' zhuó chuáng', + '长相' => ' zhǎng xiàng', + '相率' => ' xiāng shuài', + '凶相' => ' xiōng xiàng', + '窘相' => ' jiǒng xiàng', + '两重' => ' liǎng chóng', + '良将' => ' liáng jiàng', + '供状' => ' gòng zhuàng', + '强征' => ' qiǎng zhēng', + '怔忪' => ' zhēng zhōng', + '怔怔' => ' zhèng zhèng', + '跄踉' => ' qiàng liàng', + '长江' => ' cháng jiāng', + '长生' => ' cháng shēng', + '踉蹡' => ' liàng qiāng', + '重重' => ' chóng chóng', + '旋床' => ' xuàn chuáng', + '创面' => ' chuāng miàn', + '长城' => ' cháng chéng', + '创兴' => ' chuàng xīng', + '生相' => ' shēng xiàng', + '亮相' => ' liàng xiàng', + '框框' => ' kuàng kuàng', + '铛铛' => ' chēng chēng', + '长帅' => ' cháng shuài', + '乡长' => ' xiāng cháng', + '掌相' => ' zhǎng xiàng', + '钻床' => ' zuàn chuáng', + '创痛' => ' chuāng tòng', + '长征' => ' cháng zhēng', + '更爽' => ' gēng shuǎng', + '称量' => ' chēng liáng', + '重光' => ' chóng guāng', + '重唱' => ' chóng chàng', + '上相' => ' shàng xiàng', + '汤汤' => ' shāng shāng', + '少壮' => ' shào zhuàng', + '踉跄' => ' liàng qiàng', + '征传' => ' zhēng zhuàn', + '绷床' => ' bēng chuáng', + '装相' => ' zhuāng xiàng', + '将帅' => ' jiàng shuài', + '丈量' => ' zhàng liáng', + '中伤' => ' zhòng shāng', + '商量' => ' shāng liáng', + '正传' => ' zhèng zhuàn', + '上将' => ' shàng jiàng', + '泷水' => ' shuāng shuǐ', + '创伤' => ' chuāng shāng', + '重创' => ' zhòng chuāng', + '冲床' => ' chòng chuáng', + '挣揣' => ' zhèng chuài', + '双重' => ' shuāng chóng', + '窗框' => ' chuāng kuàng', + '闯将' => ' chuǎng jiàng', + '靓装' => ' liàng zhuāng', + '场长' => ' cháng zhǎng', + '政争' => ' zhèng zhēng', + '乘胜' => ' chéng shèng', + '降将' => ' xiáng jiàng', + '上声' => ' shǎng shēng', + '劲急' => ' jìng jí', + '长川' => ' cháng chuān', + '专长' => ' zhuān cháng', + '镗床' => ' táng chuáng', + '中奖' => ' zhòng jiǎng', + '相向' => ' xiāng xiàng', + '长长' => ' cháng cháng', + '种粮' => ' zhòng liáng', + '揣想' => ' chuǎi xiǎng', + '相像' => ' xiāng xiàng', + '中将' => ' zhōng jiàng', + '丞相' => ' chéng xiàng', + '相声' => ' xiàng sheng', + '相框' => ' xiàng kuàng', + '黄裳' => ' huáng cháng', + '中长' => ' zhōng cháng', + '长虫' => ' cháng chóng', + '双杠' => ' shuāng gàng', + '晃晃' => ' huàng huǎng', + '正长' => ' zhèng cháng', + '长程' => ' cháng chéng', + '抢种' => ' qiǎng zhòng', + '中枪' => ' zhòng qiāng', + '强抢' => ' qiáng qiǎng', + '强将' => ' qiáng jiàng', + '跄跄' => ' qiàng qiàng', + '量程' => ' liáng chéng', + '兵长' => ' bīng cháng', + '少将' => ' shào jiàng', + '长剑' => ' cháng jiàn', + '间种' => ' jiàn zhòng', + '重茧' => ' chóng jiǎn', + '监生' => ' jiàn shēng', + '重放' => ' chóng fàng', + '手相' => ' shǒu xiàng', + '健将' => ' jiàn jiàng', + '将校' => ' jiàng xiào', + '唱片' => ' chàng piān', + '丧荒' => ' sāng huāng', + '长红' => ' cháng hóng', + '乘间' => ' chéng jiàn', + '长工' => ' cháng gōng', + '长风' => ' cháng fēng', + '长方' => ' cháng fāng', + '长调' => ' cháng diào', + '厂甸' => ' chǎng diàn', + '商汤' => ' shāng tāng', + '哮喘' => ' xiào chuǎn', + '抽中' => ' chōu zhòng', + '长编' => ' cháng biān', + '长康' => ' cháng kāng', + '重趼' => ' chóng jiǎn', + '冲孔' => ' chòng kǒng', + '长勺' => ' cháng sháo', + '长啸' => ' cháng xiào', + '长洲' => ' cháng zhōu', + '长斋' => ' cháng zhāi', + '长圆' => ' cháng yuán', + '长缨' => ' cháng yīng', + '工长' => ' gōng cháng', + '长行' => ' cháng xíng', + '昌兴' => ' chāng xīng', + '长性' => ' cháng xìng', + '长笑' => ' cháng xiào', + '小传' => ' xiǎo zhuàn', + '成行' => ' chéng háng', + '长痛' => ' cháng tòng', + '长亭' => ' cháng tíng', + '长天' => ' cháng tiān', + '长松' => ' cháng sōng', + '盟长' => ' méng cháng', + '更香' => ' gēng xiāng', + '丧钟' => ' sāng zhōng', + '重瞳' => ' zhòng tóng', + '重山' => ' chóng shān', + '将令' => ' jiàng lìng', + '长身' => ' cháng shēn', + '长山' => ' cháng shān', + '悄声' => ' qiǎo shēng', + '峥巆' => ' zhēng yíng', + '彷徨' => ' páng huáng', + '点种' => ' diǎn zhòng', + '重圆' => ' chóng yuán', + '春种' => ' chūn zhòng', + '创痕' => ' chuāng hén', + '揣情' => ' chuǎi qíng', + '应征' => ' yìng zhēng', + '杆状' => ' gǎn zhuàng', + '川藏' => ' chuān zàng', + '莨绸' => ' liáng chóu', + '端量' => ' duān liáng', + '倒床' => ' dǎo chuáng', + '巷弄' => ' xiàng lòng', + '冯生' => ' píng shēng', + '警长' => ' jǐng cháng', + '疯长' => ' fēng cháng', + '天长' => ' tiān cháng', + '怪相' => ' guài xiàng', + '了账' => ' liǎo zhàng', + '囊膪' => ' nāng chuài', + '囊揣' => ' nāng chuài', + '鼎铛' => ' dǐng chēng', + '空转' => ' kōng zhuàn', + '光栅' => ' guāng shān', + '长陵' => ' cháng líng', + '专横' => ' zhuān hèng', + '长卷' => ' cháng juàn', + '长庆' => ' cháng qìng', + '长桥' => ' cháng qiáo', + '承应' => ' chéng yìng', + '将领' => ' jiàng lǐng', + '将官' => ' jiàng guān', + '长鸣' => ' cháng míng', + '长命' => ' cháng mìng', + '商行' => ' shāng háng', + '短长' => ' duǎn cháng', + '长青' => ' cháng qīng', + '黄钻' => ' huáng zuàn', + '重行' => ' chóng xíng', + '场院' => ' cháng yuàn', + '方框' => ' fāng kuàng', + '帐棚' => ' zhàng peng', + '连中' => ' lián zhòng', + '强横' => ' qiáng hèng', + '冲调' => ' chōng tiáo', + '强劲' => ' qiáng jìng', + '专差' => ' zhuān chāi', + '名将' => ' míng jiàng', + '桑葚' => ' sāng shèn', + '秤杆' => ' chèng gǎn', + '睡觉' => ' shuì jiào', + '矫情' => ' jiáo qíng', + '供桌' => ' gòng zhuō', + '杠荡' => ' gàng dàng', + '杠铃' => ' gàng líng', + '相干' => ' xiāng gān', + '瞭望' => ' liào wàng', + '枞阳' => ' zōng yáng', + '干重' => ' gān zhòng', + '肇兴' => ' zhào xīng', + '相国' => ' xiàng guó', + '疏率' => ' shū shuài', + '应选' => ' yìng xuǎn', + '崆峒' => ' kōng tóng', + '筵上' => ' yán shǎng', + '将佐' => ' jiàng zuǒ', + '套种' => ' tào zhòng', + '当真' => ' dàng zhēn', + '槟榔' => ' bīng láng', + '应援' => ' yìng yuán', + '专著' => ' zhuān zhù', + '相士' => ' xiàng shì', + '干娘' => ' gān niáng', + '光晕' => ' guāng yùn', + '睡着' => ' shuì zháo', + '乾县' => ' qián xiàn', + '直率' => ' zhí shuài', + '拱券' => ' gǒng xuàn', + '长眼' => ' cháng yǎn', + '炸酱' => ' zhá jiàng', + '扎挣' => ' zhá zhēng', + '斋供' => ' zhāi gòng', + '张拓' => ' zhāng tuò', + '侧棱' => ' zhāi léng', + '看相' => ' kàn xiàng', + '相位' => ' xiàng wèi', + '看中' => ' kàn zhòng', + '占梦' => ' zhān mèng', + '眄眄' => ' miàn miàn', + '久长' => ' jiǔ cháng', + '相纸' => ' xiàng zhǐ', + '相处' => ' xiāng chǔ', + '乐章' => ' yuè zhāng', + '少年' => ' shào nián', + '相架' => ' xiàng jià', + '瞭哨' => ' liào shào', + '奠定' => ' diàn dìng', + '正处' => ' zhèng chǔ', + '中暑' => ' zhòng shǔ', + '广为' => ' guǎng wéi', + '了了' => ' liǎo liǎo', + '乾陵' => ' qián líng', + '称为' => ' chēng wéi', + '干姜' => ' gān jiāng', + '种花' => ' zhòng huā', + '横行' => ' héng xíng', + '种树' => ' zhòng shù', + '种植' => ' zhòng zhí', + '称钱' => ' chèn qián', + '椆苕' => ' diào tiáo', + '乾隆' => ' qián lóng', + '症结' => ' zhēng jié', + '广乐' => ' guǎng yuè', + '将门' => ' jiàng mén', + '了当' => ' liǎo dàng', + '屏营' => ' bīng yíng', + '光杆' => ' guāng gǎn', + '棕绷' => ' zōng bēng', + '穷尽' => ' qióng jìn', + '槟州' => ' bīng zhōu', + '检校' => ' jiǎn jiào', + '减削' => ' jiǎn xiāo', + '穹肋' => ' qíong lèi', + '痴长' => ' chī cháng', + '岭巆' => ' lǐng yíng', + '将牌' => ' jiàng pái', + '校雠' => ' jiào chóu', + '交卷' => ' jiāo juàn', + '校点' => ' jiào diǎn', + '应身' => ' yìng shēn', + '扛鼎' => ' gāng dǐng', + '笼罩' => ' lǒng zhào', + '杠房' => ' gàng fáng', + '交差' => ' jiāo chāi', + '归降' => ' guī xiáng', + '空调' => ' kōng tiáo', + '挣开' => ' zhèng kāi', + '笼槛' => ' lóng jiàn', + '应天' => ' yìng tiān', + '简朴' => ' jiǎn piáo', + '当天' => ' dàng tiān', + '笼统' => ' lǒng tǒng', + '更变' => ' gēng biàn', + '属相' => ' shǔ xiàng', + '将尉' => ' jiàng wèi', + '空闲' => ' kòng xián', + '好胜' => ' hào shèng', + '中彩' => ' zhòng cǎi', + '兴建' => ' xīng jiàn', + '唪经' => ' běng jīng', + '烹调' => ' pēng tiáo', + '晃着' => ' huàng zhe', + '兴平' => ' xīng píng', + '黄晕' => ' huáng yùn', + '兴宁' => ' xīng níng', + '拽文' => ' zhuài wén', + '封禅' => ' fēng shàn', + '抓差' => ' zhuā chāi', + '兴亡' => ' xīng wáng', + '为生' => ' wéi shēng', + '佣钱' => ' yòng qián', + '为重' => ' wéi zhòng', + '兴兵' => ' xīng bīng', + '校样' => ' jiào yàng', + '好尚' => ' hào shàng', + '考量' => ' kǎo liáng', + '行款' => ' háng kuǎn', + '老将' => ' lǎo jiàng', + '央行' => ' yāng háng', + '种瓜' => ' zhòng guā', + '审校' => ' shěn jiào', + '照片' => ' zhào piān', + '主将' => ' zhǔ jiàng', + '翘棱' => ' qiáo lēng', + '过长' => ' guò cháng', + '饮场' => ' yìn chǎng', + '左传' => ' zuǒ zhuàn', + '工行' => ' gōng háng', + '绍兴' => ' shào xīng', + '框架' => ' kuàng jià', + '滚转' => ' gǔn zhuàn', + '用间' => ' yòng jiàn', + '缴卷' => ' jiǎo juàn', + '工坊' => ' gōng fáng', + '纯朴' => ' chún piáo', + '脑涨' => ' nǎo zhàng', + '应龙' => ' yìng lóng', + '狭长' => ' xiá cháng', + '伙种' => ' huǒ zhòng', + '三重' => ' sān chóng', + '大黄' => ' dài huáng', + '供应' => ' gōng yìng', + '供奉' => ' gòng fèng', + '胶粘' => ' jiāo nián', + '金相' => ' jīn xiàng', + '照应' => ' zhào yìng', + '种痘' => ' zhòng dòu', + '行帮' => ' háng bāng', + '尽忠' => ' jìn zhōng', + '云裳' => ' yún cháng', + '少间' => ' shǎo jiàn', + '社长' => ' shè cháng', + '少校' => ' shào xiào', + '乐正' => ' yuè zhèng', + '供款' => ' gòng kuǎn', + '中邪' => ' zhòng xié', + '好强' => ' hào qiáng', + '供暖' => ' gòng nuǎn', + '中肯' => ' zhòng kěn', + '远兴' => ' yuǎn xīng', + '家种' => ' jiā zhòng', + '更行' => ' gēng xíng', + '横杠' => ' héng gàng', + '更定' => ' gēng dìng', + '干粮' => ' gān liáng', + '更更' => ' gēng gēng', + '见年' => ' xiàn nián', + '原卷' => ' yuán juàn', + '枪杆' => ' qiāng gǎn', + '禅让' => ' shàn ràng', + '中弹' => ' zhòng dàn', + '碾坊' => ' niǎn fáng', + '乐声' => ' yuè shēng', + '翘望' => ' qiáo wàng', + '片名' => ' piān míng', + '翘首' => ' qiáo shǒu', + '上头' => ' shàng tou', + '实相' => ' shí xiàng', + '肖邦' => ' xiāo bāng', + '肖扬' => ' xiāo yáng', + '爪蟾' => ' zhuǎ chán', + '婵媛' => ' chán yuán', + '种牛' => ' zhòng niú', + '洋行' => ' yáng háng', + '羊圈' => ' yáng juàn', + '兼差' => ' jiān chāi', + '差遣' => ' chāi qiǎn', + '豁亮' => ' huò liàng', + '中舍' => ' zhōng shè', + '宁愿' => ' nìng yuàn', + '声乐' => ' shēng yuè', + '帑藏' => ' tǎng zàng', + '画框' => ' huà kuàng', + '将士' => ' jiàng shì', + '矿难' => ' kuàng nàn', + '越长' => ' yuè cháng', + '诱降' => ' yòu xiáng', + '胸闷' => ' xīong mēn', + '乾光' => ' qián guāng', + '拖拽' => ' tuō zhuài', + '转来' => ' zhuàn lái', + '炸两' => ' zhá liǎng', + '左强' => ' zuǒ jiàng', + '航行' => ' háng xíng', + '修长' => ' xiū cháng', + '垫圈' => ' diàn juàn', + '嘴长' => ' zuǐ cháng', + '炒更' => ' chǎo gēng', + '转为' => ' zhuǎn wéi', + '填空' => ' tián kòng', + '宰相' => ' zǎi xiàng', + '兴隆' => ' xīng lóng', + '兴坏' => ' xīng huài', + '话长' => ' huà cháng', + '详尽' => ' xiáng jìn', + '便嬛' => ' pián xuān', + '干证' => ' gān zhèng', + '萎黄' => ' wěi huáng', + '浆纸' => ' jiàng zhǐ', + '弹簧' => ' tán huáng', + '便便' => ' pián pián', + '兴讼' => ' xīng sòng', + '保长' => ' bǎo cháng', + '兴荣' => ' xīng róng', + '便溺' => ' biàn niào', + '倥侗' => ' kōng tóng', + '苍劲' => ' cāng jìng', + '年少' => ' nián shào', + '月相' => ' yuè xiàng', + '公差' => ' gōng chāi', + '兴庆' => ' xīng qìng', + '九转' => ' jiǔ zhuàn', + '公共' => ' gōng gòng', + '观塘' => ' guàn táng', + '船只' => ' chuán zhī', + '宫观' => ' gōng guàn', + '都长' => ' dōu cháng', + '钻钻' => ' zuàn zuàn', + '东兴' => ' dōng xīng', + '兴贤' => ' xīng xián', + '万乘' => ' wàn shèng', + '诈降' => ' zhà xiáng', + '和熊' => ' huó xióng', + '兴能' => ' xīng néng', + '洋壳' => ' yáng qiào', + '东渐' => ' dōng jiān', + '兴邦' => ' xīng bāng', + '芳甸' => ' fāng diàn', + '夏种' => ' xià zhòng', + '偏长' => ' piān cháng', + '中签' => ' zhòng qiān', + '中甸' => ' zhōng diàn', + '中标' => ' zhòng biāo', + '折床' => ' shé chuáng', + '中风' => ' zhòng fēng', + '串供' => ' chuàn gòng', + '相应' => ' xiāng yìng', + '攘场' => ' rǎng cháng', + '命中' => ' mìng zhòng', + '相公' => ' xiàng gōng', + '招降' => ' zhāo xiáng', + '深长' => ' shēn cháng', + '遣将' => ' qiǎn jiàng', + '戆直' => ' zhuàng zhí', + '营长' => ' yíng cháng', + '幢幡' => ' zhuàng fān', + '周正' => ' zhōu zhēng', + '相角' => ' xiàng jiǎo', + '撞倒' => ' zhuàng dǎo', + '中觉' => ' zhōng jiào', + '片长' => ' piàn cháng', + '中招' => ' zhòng zhāo', + '中兴' => ' zhōng xīng', + '涨满' => ' zhàng mǎn', + '状子' => ' zhuàng zǐ', + '倒帐' => ' dǎo zhàng', + '松茸' => ' sōng róng', + '兜率' => ' dōu shuài', + '兴行' => ' xīng xíng', + '会长' => ' huì cháng', + '弹唱' => ' tán chàng', + '桩子' => ' zhuāng zǐ', + '兴工' => ' xīng gōng', + '飞将' => ' fēi jiàng', + '兴县' => ' xīng xiàn', + '中选' => ' zhòng xuǎn', + '垦种' => ' kěn zhòng', + '试种' => ' shì zhòng', + '掂量' => ' diān liang', + '周长' => ' zhōu cháng', + '相片' => ' xiàng piān', + '相称' => ' xiāng chèn', + '劝降' => ' quàn xiáng', + '瘦长' => ' shòu cháng', + '长钱' => ' cháng qián', + '洋相' => ' yáng xiàng', + '钻工' => ' zuàn gōng', + '廊坊' => ' láng fáng', + '相貌' => ' xiàng mào', + '行间' => ' háng jiān', + '卷面' => ' juàn miàn', + '张角' => ' zhāng jué', + '强求' => ' qiǎng qiú', + '漫长' => ' màn cháng', + '屯邅' => ' zhūn zhān', + '斗转' => ' dǒu zhuǎn', + '幸甚' => ' xìng shèn', + '冲劲' => ' chòng jìn', + '草率' => ' cǎo shuài', + '吊丧' => ' diào sāng', + '还钱' => ' huán qián', + '行当' => ' háng dāng', + '卷帘' => ' juàn lián', + '漂零' => ' piāo líng', + '削面' => ' xiāo miàn', + '强嘴' => ' jiàng zuǐ', + '行情' => ' háng qíng', + '小卷' => ' xiǎo juàn', + '凶煞' => ' xiōng shà', + '朝阳' => ' zhāo yáng', + '还阳' => ' huán yáng', + '相切' => ' xiāng qiē', + '着边' => ' zhuó biān', + '漂荡' => ' piāo dàng', + '着手' => ' zhuó shǒu', + '小差' => ' xiǎo chāi', + '倒相' => ' dào xiàng', + '定兴' => ' dìng xīng', + '着忙' => ' zháo máng', + '海相' => ' hǎi xiàng', + '卷首' => ' juàn shǒu', + '定当' => ' dìng dàng', + '位相' => ' wèi xiàng', + '蟏蛸' => ' xiāo shāo', + '外传' => ' wài zhuàn', + '乡侯' => ' xiāng hòu', + '圈养' => ' juàn yǎng', + '张华' => ' zhāng huà', + '为政' => ' wéi zhèng', + '螵蛸' => ' piāo xiāo', + '康乾' => ' kāng qián', + '够戗' => ' gòu qiàng', + '著称' => ' zhù chēng', + '倒账' => ' dǎo zhàng', + '还童' => ' huán tóng', + '官差' => ' guān chāi', + '充分' => ' chōng fèn', + '卷卷' => ' juàn juàn', + '短供' => ' duǎn gòng', + '蒙山' => ' měng shān', + '钻攻' => ' zuàn gōng', + '下乘' => ' xià shèng', + '荫凉' => ' yìn liáng', + '傧相' => ' bīn xiàng', + '僮族' => ' zhuàng zú', + '本相' => ' běn xiàng', + '多重' => ' duō chóng', + '朝鲜' => ' cháo xiǎn', + '兴旺' => ' xīng wàng', + '蒙茸' => ' méng róng', + '看场' => ' kān chǎng', + '蜀相' => ' shǔ xiàng', + '荥经' => ' yíng jīng', + '鲜见' => ' xiǎn jiàn', + '倥偬' => ' kǒng zǒng', + '蒜茸' => ' suàn róng', + '盖上' => ' gài shang', + '滇藏' => ' diān zàng', + '沧浪' => ' cāng láng', + '蓬茸' => ' péng róng', + '守更' => ' shǒu gēng', + '浅鲜' => ' qiǎn xiǎn', + '传略' => ' zhuàn lüè', + '干将' => ' gàn jiàng', + '延长' => ' yán cháng', + '大城' => ' dài chéng', + '倔强' => ' jué jiàng', + '漂洋' => ' piāo yáng', + '沉着' => ' chén zhuó', + '萧乾' => ' xiāo qián', + '蚌山' => ' bèng shān', + '哗众' => ' huá zhòng', + '守丧' => ' shǒu sāng', + '嬛嬛' => ' xuān xuān', + '荐椎' => ' jiàn zhuī', + '淳朴' => ' chún piáo', + '永兴' => ' yǒng xīng', + '哄哄' => ' hǒng hǒng', + '建行' => ' jiàn háng', + '哄弄' => ' hǒng nòng', + '弄堂' => ' lòng táng', + '藏羚' => ' zàng líng', + '江干' => ' jiāng gān', + '藏青' => ' zàng qīng', + '传赞' => ' zhuàn zàn', + '弄脏' => ' nòng zāng', + '叨教' => ' tāo jiào', + '兴山' => ' xīng shān', + '切断' => ' qiē duàn', + '脊椎' => ' jǐ zhuī', + '兴业' => ' xīng yè', + '离间' => ' lí jiàn', + '移行' => ' yí háng', + '供词' => ' gòng cí', + '飘泊' => ' piāo bó', + '朴雅' => ' piáo yǎ', + '散匪' => ' sǎn fěi', + '马圈' => ' mǎ juàn', + '口角' => ' kǒu jué', + '兴安' => ' xīng ān', + '散射' => ' sǎn shè', + '书卷' => ' shū juàn', + '崩倒' => ' bēng dǎo', + '撩人' => ' liáo rén', + '燕赵' => ' yān zhào', + '背榜' => ' bēi bǎng', + '不揣' => ' bù chuǎi', + '为准' => ' wéi zhǔn', + '更阑' => ' gēng lán', + '馕糟' => ' nǎng zāo', + '散架' => ' sǎn jià', + '择刺' => ' zhái cì', + '案称' => ' àn chèng', + '修为' => ' xiū wéi', + '压卷' => ' yā juàn', + '危难' => ' wēi nàn', + '散沙' => ' sǎn shā', + '羞臊' => ' xiū sào', + '掖庭' => ' yè tíng', + '一刬' => ' yī chàn', + '掖垣' => ' yè yuán', + '卵子' => ' luǎn zǐ', + '盐分' => ' yán fèn', + '难弹' => ' nán tán', + '推度' => ' tuī duó', + '何曾' => ' hé céng', + '擂台' => ' lèi tái', + '风靡' => ' fēng mǐ', + '雀子' => ' qiāo zǐ', + '撩拨' => ' liáo bō', + '首都' => ' shǒu dū', + '雅片' => ' yā piàn', + '养子' => ' yǎng zǐ', + '散文' => ' sǎn wén', + '起更' => ' qǐ gēng', + '笼络' => ' lǒng luò', + '为首' => ' wéi shǒu', + '兴许' => ' xīng xǔ', + '脱壳' => ' tuō qiào', + '返还' => ' fǎn huán', + '累坠' => ' léi zhuì', + '丰镐' => ' fēng hào', + '质朴' => ' zhì piáo', + '狼头' => ' láng tou', + '风镐' => ' fēng hào', + '风斗' => ' fēng dǒu', + '犍为' => ' qián wéi', + '武将' => ' wǔ jiàng', + '拽步' => ' zhuài bù', + '山查' => ' shān zhā', + '本色' => ' běn shǎi', + '拼攒' => ' pīn cuán', + '牵累' => ' qiān lěi', + '转距' => ' zhuàn jù', + '干甚' => ' gàn shèn', + '更番' => ' gēng fān', + '轧钢' => ' zhá gāng', + '体长' => ' tǐ cháng', + '粘滑' => ' nián huá', + '残卷' => ' cán juàn', + '蒙文' => ' měng wén', + '累赘' => ' léi zhuì', + '感兴' => ' gǎn xīng', + '追查' => ' zhuī zhā', + '跂想' => ' qǐ xiǎng', + '步长' => ' bù cháng', + '辩难' => ' biàn nàn', + '高更' => ' gāo gēng', + '纳降' => ' nà xiáng', + '屏除' => ' bǐng chú', + '高挑' => ' gāo tiǎo', + '梗咽' => ' gěng yān', + '屏退' => ' bǐng tuì', + '撂倒' => ' liào dǎo', + '农舍' => ' nóng shè', + '财会' => ' cái kuài', + '比量' => ' bǐ liáng', + '高着' => ' gāo zhāo', + '细长' => ' xì cháng', + '退税' => ' tuì shuì', + '掺假' => ' chān jiǎ', + '退色' => ' tuì shǎi', + '箭杆' => ' jiàn gǎn', + '框图' => ' kuàng tú', + '框子' => ' kuàng zi', + '询查' => ' xún zhā', + '切至' => ' qiē zhì', + '粘菌' => ' nián jūn', + '非分' => ' fēi fèn', + '佛教' => ' fó jiào', + '咽音' => ' yān yīn', + '龈炎' => ' yín yán', + '背篓' => ' bēi lǒu', + '背包' => ' bēi bāo', + '背带' => ' bēi dài', + '瓤子' => ' ráng zǐ', + '自省' => ' zì xǐng', + '枝蔓' => ' zhī wàn', + '魏巍' => ' wèi wēi', + '切分' => ' qiē fēn', + '眼泡' => ' yǎn pāo', + '撩惹' => ' liáo rě', + '摒弃' => ' bìng qì', + '杨子' => ' yáng zǐ', + '悄寂' => ' qiǎo jì', + '齿龈' => ' chǐ yín', + '阳子' => ' yáng zǐ', + '乾图' => ' qián tú', + '诮呵' => ' qiào hē', + '曲工' => ' qǔ gōng', + '发钗' => ' fà chāi', + '镟子' => ' xuàn zǐ', + '稽首' => ' qǐ shǒu', + '胄子' => ' zhòu zǐ', + '鸿鹄' => ' hóng hú', + '扦子' => ' qiān zǐ', + '肖似' => ' xiào sì', + '浅子' => ' qiǎn zǐ', + '撇嘴' => ' piě zuǐ', + '签子' => ' qiān zǐ', + '查探' => ' zhā tàn', + '发辫' => ' fà biàn', + '佛经' => ' fó jīng', + '选曲' => ' xuǎn qǔ', + '龟裂' => ' jūn liè', + '龈音' => ' yín yīn', + '羊子' => ' yáng zǐ', + '来头' => ' lái tou', + '玄子' => ' xuán zǐ', + '轩子' => ' xuān zǐ', + '露背' => ' lòu bèi', + '背头' => ' bēi tóu', + '露白' => ' lòu bái', + '腰杆' => ' yāo gǎn', + '任丘' => ' rén qiū', + '丽水' => ' lí shuǐ', + '翘曲' => ' qiáo qū', + '脱脱' => ' tuì tuì', + '扑棱' => ' pū lēng', + '食菌' => ' shí jùn', + '佝瞀' => ' kòu mào', + '掰扯' => ' bāi che', + '显得' => ' xiǎn de', + '反诘' => ' fǎn jié', + '提防' => ' dī fáng', + '馒头' => ' mán tou', + '推杆' => ' tuī gǎn', + '严处' => ' yán chǔ', + '青子' => ' qīng zǐ', + '拥塞' => ' yōng sè', + '翻倒' => ' fān dǎo', + '作乐' => ' zuò yuè', + '骑缝' => ' qí féng', + '禽舍' => ' qín shè', + '供给' => ' gōng jǐ', + '脊线' => ' jǐ xiàn', + '肉干' => ' ròu gān', + '使尽' => ' shǐ jìn', + '探查' => ' tàn zhā', + '难倒' => ' nán dǎo', + '摆划' => ' bǎi huá', + '作为' => ' zuò wéi', + '推倒' => ' tuī dǎo', + '兴义' => ' xīng yì', + '脾脏' => ' pí zāng', + '一朝' => ' yī zhāo', + '鸡枞' => ' jī zōng', + '压轴' => ' yā zhòu', + '颤栗' => ' zhàn lì', + '押当' => ' yā dàng', + '栅极' => ' shān jí', + '马蹬' => ' mǎ dèng', + '栅格' => ' shān gé', + '翘足' => ' qiáo zú', + '扑扇' => ' pū shān', + '伊甸' => ' yī diàn', + '隐潭' => ' yǐn tán', + '翘企' => ' qiáo qǐ', + '兴和' => ' xīng hé', + '古朴' => ' gǔ piáo', + '馆子' => ' guǎn zǐ', + '八行' => ' bā háng', + '馏分' => ' liú fèn', + '住舍' => ' zhù shè', + '散板' => ' sǎn bǎn', + '煞神' => ' shà shén', + '撒种' => ' sǎ zhǒng', + '肖恩' => ' xiāo ēn', + '泡桐' => ' pāo tóng', + '老少' => ' lǎo shào', + '豪横' => ' háo hèng', + '号叫' => ' háo jiào', + '审度' => ' shěn duó', + '处方' => ' chǔ fāng', + '栓塞' => ' shuān sè', + '校勘' => ' jiào kān', + '行号' => ' háng háo', + '孱弱' => ' chán ruò', + '黉舍' => ' hóng shè', + '宁肯' => ' nìng kěn', + '宏拓' => ' hóng tuò', + '校阅' => ' jiào yuè', + '行为' => ' xíng wéi', + '翘材' => ' qiáo cái', + '行市' => ' háng shì', + '校舍' => ' xiào shè', + '行家' => ' háng jiā', + '侯刚' => ' hòu gāng', + '行话' => ' háng huà', + '行列' => ' háng liè', + '柴火' => ' chái huō', + '缝纫' => ' féng rèn', + '接应' => ' jiē yìng', + '巷道' => ' hàng dào', + '号丧' => ' háo sāng', + '混熟' => ' hùn shóu', + '审处' => ' shěn chǔ', + '混浊' => ' hún zhuó', + '氹仔' => ' dàng zǎi', + '计量' => ' jì liáng', + '解调' => ' jiě tiáo', + '寒颤' => ' hán zhàn', + '背债' => ' bēi zhài', + '行道' => ' háng dào', + '好还' => ' hǎo huán', + '行规' => ' háng guī', + '审查' => ' shěn zhā', + '行会' => ' háng huì', + '亲家' => ' qìng jia', + '深知' => ' shēn zhì', + '解元' => ' jiè yuán', + '编著' => ' biān zhù', + '栟茶' => ' bīng chá', + '考卷' => ' kǎo juàn', + '江都' => ' jiāng dū', + '朝珠' => ' cháo zhū', + '血钻' => ' xuè zuàn', + '要功' => ' yāo gōng', + '翘楚' => ' qiáo chǔ', + '系上' => ' jì shang', + '横蛮' => ' hèng mán', + '翘盼' => ' qiáo pàn', + '行头' => ' xíng tou', + '官倒' => ' guān dǎo', + '横事' => ' hèng shì', + '行辈' => ' háng bèi', + '守分' => ' shǒu fèn', + '宅舍' => ' zhái shè', + '哄逗' => ' hǒng dòu', + '泰兴' => ' tài xīng', + '罄尽' => ' qìng jìn', + '行货' => ' háng huò', + '稖头' => ' bàng tou', + '炳著' => ' bǐng zhù', + '混蒙' => ' hùn mēng', + '混行' => ' hún xíng', + '调酒' => ' tiáo jǐu', + '调适' => ' tiáo shì', + '供稿' => ' gòng gǎo', + '摔打' => ' shuāi dá', + '泡面' => ' pāo miàn', + '绕腾' => ' rào teng', + '挣得' => ' zhèng dé', + '宝钻' => ' bǎo zuàn', + '美差' => ' měi chāi', + '治丧' => ' zhì sāng', + '季相' => ' jì xiàng', + '罗甸' => ' luó diàn', + '蛮横' => ' mán hèng', + '办差' => ' bàn chāi', + '户长' => ' hù cháng', + '沙参' => ' shā shēn', + '校对' => ' jiào duì', + '罐头' => ' guàn tou', + '校验' => ' jiào yàn', + '波长' => ' bō cháng', + '绷带' => ' bēng dài', + '补种' => ' bǔ zhòng', + '雹霰' => ' báo xiàn', + '袅娜' => ' niǎo nuó', + '扫帚' => ' sào zhǒu', + '裁缝' => ' cái féng', + '绷紧' => ' bēng jǐn', + '室町' => ' shì tǐng', + '抱朴' => ' bào piáo', + '浪头' => ' làng tou', + '褪色' => ' tuì shǎi', + '脏话' => ' zāng huà', + '跟差' => ' gēn chāi', + '脏弹' => ' zāng dàn', + '差派' => ' chāi pài', + '更楼' => ' gēng lóu', + '燕京' => ' yān jīng', + '蒙难' => ' méng nàn', + '煎炸' => ' jiān zhá', + '转去' => ' zhuàn qù', + '干冷' => ' gān lěng', + '干连' => ' gān lián', + '壳牌' => ' qiào pái', + '较为' => ' jiào wéi', + '较著' => ' jiào zhù', + '拶刑' => ' zǎn xíng', + '转速' => ' zhuàn sù', + '转鼓' => ' zhuàn gǔ', + '轘裂' => ' huàn liè', + '粗率' => ' cū shuài', + '松散' => ' sōng sǎn', + '烘干' => ' hōng gān', + '香几' => ' xiāng jī', + '红晕' => ' hóng yùn', + '脊梁' => ' jǐ liáng', + '蔓菁' => ' mán jīng', + '拓展' => ' tuò zhǎn', + '蔡甸' => ' cài diàn', + '更新' => ' gēng xīn', + '差使' => ' chāi shǐ', + '差事' => ' chāi shì', + '该着' => ' gāi zháo', + '更改' => ' gēng gǎi', + '烟卷' => ' yān juàn', + '殷红' => ' yān hóng', + '桔梗' => ' jié gěng', + '干柴' => ' gān chái', + '脏煤' => ' zāng méi', + '归省' => ' guī xǐng', + '更漏' => ' gēng lòu', + '载明' => ' zǎi míng', + '载湉' => ' zǎi tián', + '燕山' => ' yān shān', + '粘结' => ' nián jié', + '肮脏' => ' āng zāng', + '更为' => ' gèng wéi', + '拙著' => ' zhuō zhù', + '粘滞' => ' nián zhì', + '归还' => ' guī huán', + '特长' => ' tè cháng', + '更代' => ' gēng dài', + '总得' => ' zǒng děi', + '嚎丧' => ' háo sāng', + '揣测' => ' chuǎi cè', + '柴门' => ' zhài mén', + '寒伧' => ' hán chen', + '揣摩' => ' chuǎi mó', + '净尽' => ' jìng jìn', + '有空' => ' yǒu kòng', + '换帖' => ' huàn tiě', + '好闲' => ' hào xián', + '被卷' => ' bèi juàn', + '淋病' => ' lìn bìng', + '深信' => ' shēn xìn', + '蜕壳' => ' tuì qiào', + '宿将' => ' sù jiàng', + '蜚蠊' => ' fěi lián', + '蝃蝥' => ' zhuō máo', + '家当' => ' jiā dàng', + '海兴' => ' hǎi xīng', + '翻供' => ' fān gòng', + '缝制' => ' féng zhì', + '宫阙' => ' gōng què', + '海参' => ' hǎi shēn', + '缝絍' => ' féng rèn', + '有朝' => ' yǒu zhāo', + '能耐' => ' néng nài', + '转磨' => ' zhuàn mò', + '糨糊' => ' jiàng hù', + '转矩' => ' zhuàn jǔ', + '争得' => ' zhēng de', + '转塔' => ' zhuàn tǎ', + '转子' => ' zhuàn zǐ', + '更迭' => ' gēng dié', + '更始' => ' gēng shǐ', + '片头' => ' piān tóu', + '转椅' => ' zhuàn yǐ', + '身处' => ' shēn chǔ', + '曾孙' => ' zēng sūn', + '身分' => ' shēn fèn', + '转炉' => ' zhuàn lú', + '糨子' => ' jiàng zǐ', + '部将' => ' bù jiàng', + '蕉萃' => ' qiáo cuì', + '未曾' => ' wèi zēng', + '拳头' => ' quán tou', + '身为' => ' shēn wéi', + '煮熟' => ' zhǔ shóu', + '处身' => ' chǔ shēn', + '面糊' => ' miàn hù', + '面的' => ' miàn dí', + '供果' => ' gòng guǒ', + '处处' => ' chǔ chù', + '为下' => ' wéi xià', + '朝雨' => ' zhāo yǔ', + '蝇子' => ' yíng zǐ', + '萎谢' => ' wěi xiè', + '为学' => ' wéi xué', + '为是' => ' wéi shì', + '公子' => ' gōng zǐ', + '裁切' => ' cái qiē', + '裁处' => ' cái chǔ', + '公仆' => ' gōng pú', + '元曲' => ' yuán qǔ', + '号啕' => ' háo táo', + '婉娩' => ' wǎn wǎn', + '视为' => ' shì wéi', + '万石' => ' wàn dàn', + '有为' => ' yǒu wéi', + '见得' => ' jiàn de', + '蚌埠' => ' bèng bù', + '要求' => ' yāo qiú', + '要晕' => ' yāo yūn', + '要挟' => ' yāo xié', + '为文' => ' wéi wén', + '血晕' => ' xiě yùn', + '要塞' => ' yào sài', + '衣冠' => ' yì guān', + '藏獒' => ' zàng áo', + '处置' => ' chǔ zhì', + '角子' => ' jiǎo zǐ', + '蚂螂' => ' mā láng', + '优游' => ' yōu yóu', + '望都' => ' wàng dū', + '螺杆' => ' luó gǎn', + '萎落' => ' wěi luò', + '衣着' => ' yī zhuó', + '朝夕' => ' zhāo xī', + '崴嵬' => ' wēi wéi', + '行距' => ' háng jù', + '为然' => ' wéi rán', + '行语' => ' háng yǔ', + '朝歌' => ' zhāo gē', + '行业' => ' háng yè', + '朝气' => ' zhāo qì', + '问难' => ' wèn nàn', + '为数' => ' wéi shù', + '为头' => ' wéi tóu', + '唯唯' => ' wěi wěi', + '要好' => ' yāo hǎo', + '裁度' => ' cái duó', + '停泊' => ' tíng bó', + '轧辊' => ' zhá gǔn', + '下切' => ' xià qiē', + '特供' => ' tè gòng', + '蔚为' => ' wèi wéi', + '软呢' => ' ruǎn ní', + '蔚县' => ' yù xiàn', + '藤子' => ' téng zǐ', + '切杆' => ' qiē gān', + '轩掖' => ' xuān yè', + '俶傥' => ' tì tǎng', + '轧制' => ' zhá zhì', + '下帖' => ' xià tiě', + '切口' => ' qiē kǒu', + '下处' => ' xià chǔ', + '更衣' => ' gēng yī', + '切切' => ' qiē qiē', + '切刀' => ' qiē dāo', + '天得' => ' tiān de', + '蕃茄' => ' fān qié', + '天都' => ' tiān dū', + '车斗' => ' chē dǒu', + '躯壳' => ' qū qiào', + '叨扰' => ' tāo rǎo', + '下头' => ' xià tou', + '西藏' => ' xī zàng', + '尽早' => ' jìn zǎo', + '虾干' => ' xiā gān', + '僮仆' => ' tóng pú', + '望子' => ' wàng zǐ', + '汪子' => ' wāng zǐ', + '萎败' => ' wěi bài', + '免得' => ' miǎn de', + '褪下' => ' tùn xià', + '俭薄' => ' jiǎn bó', + '萎顿' => ' wěi dùn', + '蝳蝐' => ' dài mào', + '唐子' => ' táng zǐ', + '服丧' => ' fú sāng', + '为害' => ' wéi hài', + '嗡子' => ' wēng zǐ', + '着迷' => ' zháo mí', + '藏族' => ' zàng zú', + '梃子' => ' tǐng zǐ', + '轻薄' => ' qīng bó', + '轻子' => ' qīng zǐ', + '更次' => ' gēng cì', + '堂子' => ' táng zǐ', + '冠子' => ' guàn zi', + '图卷' => ' tú juàn', + '蹄髈' => ' tí pǎng', + '舌苔' => ' shé tāi', + '甚的' => ' shèn de', + '数落' => ' shǔ luò', + '北斗' => ' běi dǒu', + '敛巴' => ' liǎn ba', + '村舍' => ' cūn shè', + '斗六' => ' dǒu lìu', + '挑拔' => ' tiǎo bá', + '包干' => ' bāo gān', + '神似' => ' shén sì', + '兴起' => ' xīng qǐ', + '北碚' => ' běi bèi', + '逃难' => ' táo nàn', + '曲靖' => ' qǔ jìng', + '木椆' => ' mù zhòu', + '蕴藉' => ' yùn jiè', + '腿杆' => ' tuǐ gǎn', + '最为' => ' zuì wéi', + '认识' => ' rèn shi', + '会计' => ' kuài jì', + '认为' => ' rèn wéi', + '伞菌' => ' sǎn jùn', + '数数' => ' shǔ shù', + '数出' => ' shǔ chū', + '处世' => ' chǔ shì', + '午觉' => ' wǔ jiào', + '间隙' => ' jiàn xì', + '镯子' => ' zhuó zǐ', + '躺倒' => ' tǎng dǎo', + '斗门' => ' dǒu mén', + '沈思' => ' chén sī', + '间壁' => ' jiàn bì', + '少子' => ' shǎo zǐ', + '梢子' => ' shāo zǐ', + '半分' => ' bàn fēn', + '开衩' => ' kāi chà', + '汇差' => ' huì chā', + '开杆' => ' kāi gǎn', + '开拓' => ' kāi tuò', + '数九' => ' shǔ jiǔ', + '舍亲' => ' shè qīn', + '舍人' => ' shè rén', + '苦差' => ' kǔ chāi', + '杓子' => ' sháo zi', + '十干' => ' shí gān', + '斗胆' => ' dǒu dǎn', + '倒坍' => ' dǎo tān', + '备查' => ' bèi zhā', + '诘问' => ' jié wèn', + '曾都' => ' zēng dū', + '瞳子' => ' tóng zǐ', + '调速' => ' tiáo sù', + '藏独' => ' zàng dú', + '调资' => ' tiáo zī', + '痛恶' => ' tòng wù', + '调色' => ' tiáo sè', + '筒子' => ' tǒng zǐ', + '桶子' => ' tǒng zǐ', + '桐子' => ' tóng zǐ', + '铜子' => ' tóng zǐ', + '最差' => ' zuì chā', + '凳子' => ' dèng zǐ', + '冠词' => ' guàn cí', + '调皮' => ' tiáo pí', + '调理' => ' tiáo lǐ', + '冠以' => ' guàn yǐ', + '做为' => ' zuò wéi', + '调拨' => ' tiáo bō', + '调戏' => ' tiáo xì', + '调和' => ' tiáo hé', + '透切' => ' tòu qiē', + '调剂' => ' tiáo jì', + '童仆' => ' tóng pú', + '铜模' => ' tóng mú', + '月分' => ' yuè fèn', + '解数' => ' xiè shù', + '木栅' => ' mù shān', + '处事' => ' chǔ shì', + '傀儡' => ' kuǐ lěi', + '家伙' => ' jiā huo', + '拓殖' => ' tuò zhí', + '处在' => ' chǔ zài', + '月晕' => ' yuè yùn', + '月氏' => ' ròu zhī', + '处暑' => ' chǔ shǔ', + '解廌' => ' xiè zhì', + '铜佛' => ' tóng fó', + '角斗' => ' jué dòu', + '歪货' => ' wǎi huò', + '处决' => ' chǔ jué', + '外切' => ' wài qiē', + '角逐' => ' jué zhú', + '处治' => ' chǔ zhì', + '处分' => ' chǔ fèn', + '处男' => ' chǔ nán', + '五通' => ' wǔ tòng', + '藏语' => ' zàng yǔ', + '躲难' => ' duǒ nàn', + '蕃衍' => ' fán yǎn', + '叶韵' => ' xié yùn', + '供物' => ' gòng wù', + '腰折' => ' yāo shé', + '电锯' => ' diàn jū', + '发卷' => ' fā juàn', + '搭挡' => ' dā dàng', + '曲蟮' => ' qǔ shàn', + '挨冻' => ' ái dòng', + '搭当' => ' dā dàng', + '佛性' => ' fó xìng', + '架式' => ' jià shi', + '脏字' => ' zāng zì', + '电荷' => ' diàn hè', + '揭载' => ' jiē zǎi', + '名曲' => ' míng qǔ', + '脏土' => ' zāng tǔ', + '曲静' => ' qǔ jìng', + '散列' => ' sǎn liè', + '难处' => ' nán chǔ', + '卷须' => ' juàn xū', + '恰切' => ' qià qiē', + '难为' => ' nán wéi', + '查看' => ' zhā kàn', + '佛山' => ' fó shān', + '佛冈' => ' fó gāng', + '颓萎' => ' tuí wěi', + '担懮' => ' dān yōu', + '发廊' => ' fà láng', + '搜查' => ' sōu zhā', + '畜产' => ' xù chǎn', + '改为' => ' gǎi wéi', + '佛坪' => ' fó píng', + '切开' => ' qiē kāi', + '佛典' => ' fó diǎn', + '摇杆' => ' yáo gǎn', + '耍子' => ' shuǎ zǐ', + '发型' => ' fà xíng', + '要切' => ' yào qiē', + '掖县' => ' yè xiàn', + '发小' => ' fà xiǎo', + '教子' => ' jiào zǐ', + '耗尽' => ' hào jìn', + '也曾' => ' yě céng', + '发脚' => ' fà jiǎo', + '切花' => ' qiē huā', + '耳片' => ' ěr piān', + '胶子' => ' jiāo zǐ', + '胡同' => ' hú tòng', + '考查' => ' kǎo zhā', + '查处' => ' chá chǔ', + '胡芫' => ' hú yuán', + '攒簇' => ' cuán cù', + '撇号' => ' piě hào', + '临帖' => ' lín tiè', + '畜养' => ' xù yǎng', + '鬈发' => ' quán fà', + '音乐' => ' yīn yuè', + '阙下' => ' què xià', + '非难' => ' fēi nàn', + '鮟鱇' => ' ān kāng', + '臣子' => ' chén zǐ', + '非得' => ' fēi děi', + '叱吒' => ' chì zhà', + '鲁甸' => ' lǔ diàn', + '攘辟' => ' rǎng bì', + '让子' => ' ràng zǐ', + '临难' => ' lín nàn', + '圩镇' => ' xū zhèn', + '洋落' => ' yáng là', + '犬子' => ' quǎn zǐ', + '鹿角' => ' lù jiǎo', + '鹿茸' => ' lù róng', + '职分' => ' zhí fèn', + '可调' => ' kě tiáo', + '露怯' => ' lòu qiè', + '难民' => ' nàn mín', + '脊令' => ' jí líng', + '袷袢' => ' qiā pàn', + '暗杠' => ' àn gàng', + '颈子' => ' jǐng zǐ', + '学舍' => ' xué shè', + '叶心' => ' xié xīn', + '切人' => ' qiē rén', + '枸橼' => ' jǔ yuán', + '高头' => ' gāo tou', + '却倒' => ' què dǎo', + '乾德' => ' qián dé', + '露出' => ' lòu chū', + '腱子' => ' jiàn zǐ', + '教课' => ' jiāo kè', + '仰给' => ' yǎng jǐ', + '敢为' => ' gǎn wéi', + '脚本' => ' jué běn', + '脏污' => ' zāng wū', + '卸载' => ' xiè zǎi', + '电子' => ' diàn zǐ', + '烟杆' => ' yān gǎn', + '切屑' => ' qiē xiè', + '原子' => ' yuán zǐ', + '搪塞' => ' táng sè', + '更替' => ' gēng tì', + '薄晓' => ' bó xiǎo', + '更夫' => ' gēng fū', + '切糕' => ' qiē gāo', + '澹台' => ' tán tái', + '切磋' => ' qiē cuō', + '瘫倒' => ' tān dǎo', + '曾祖' => ' zēng zǔ', + '天姥' => ' tiān mǔ', + '西兴' => ' xī xīng', + '调气' => ' tiáo qì', + '曾子' => ' zēng zǐ', + '更卒' => ' gēng zú', + '薄产' => ' bó chǎn', + '贡嘎' => ' gòng gá', + '猫腰' => ' máo yāo', + '调息' => ' tiáo xī', + '苕溪' => ' tiáo xī', + '薄田' => ' bó tián', + '丰都' => ' fēng dū', + '豉油' => ' chǐ yóu', + '豆豉' => ' dòu chǐ', + '调序' => ' tiáo xù', + '莲都' => ' lián dū', + '切除' => ' qiē chú', + '豆佉' => ' dòu qiā', + '馅子' => ' xiàn zǐ', + '切碎' => ' qiē suì', + '逃奔' => ' táo bèn', + '着陆' => ' zhuó lù', + '着魔' => ' zháo mó', + '倒头' => ' dǎo tóu', + '阘茸' => ' tà róng', + '嗒丧' => ' tà sàng', + '线子' => ' xiàn zǐ', + '蚬子' => ' xiǎn zǐ', + '弦子' => ' xián zǐ', + '莲子' => ' lián zǐ', + '本分' => ' běn fèn', + '曲面' => ' qǔ miàn', + '刊载' => ' kān zǎi', + '辗轧' => ' zhǎn yà', + '蒙覆' => ' měng fù', + '探杆' => ' tàn gǎn', + '辟雍' => ' bì yōng', + '仙佛' => ' xiān fó', + '切韵' => ' qiē yùn', + '末了' => ' mò liǎo', + '蹊径' => ' xī jìng', + '豁然' => ' huò rán', + '点子' => ' diǎn zǐ', + '薄幸' => ' bó xìng', + '分散' => ' fēn sǎn', + '调达' => ' tiáo dá', + '跂望' => ' qì wàng', + '薄命' => ' bó mìng', + '分内' => ' fèn nèi', + '趼子' => ' jiǎn zǐ', + '更鼓' => ' gēng gǔ', + '调合' => ' tiáo hé', + '起哄' => ' qǐ hòng', + '调护' => ' tiáo hù', + '更递' => ' gēng dì', + '调级' => ' tiáo jí', + '薄情' => ' bó qíng', + '赢得' => ' yíng de', + '赚得' => ' zuàn de', + '质难' => ' zhì nàn', + '薄明' => ' bó míng', + '分外' => ' fèn wài', + '调幅' => ' tiáo fú', + '散漫' => ' sǎn màn', + '录供' => ' lù gòng', + '跌倒' => ' diē dǎo', + '调测' => ' tiáo cè', + '变得' => ' biàn de', + '厅子' => ' tīng zǐ', + '假藉' => ' jiǎ jiè', + '藉口' => ' jiè kǒu', + '藉由' => ' jiè yóu', + '藉着' => ' jiè zhe', + '谢帖' => ' xiè tiě', + '帖文' => ' tiě wén', + '帖学' => ' tiè xué', + '藏掖' => ' cáng yè', + '曾朴' => ' zēng pǔ', + '听子' => ' tīng zǐ', + '佻薄' => ' tiāo bó', + '薄酬' => ' bó chóu', + '踺子' => ' jiàn zǐ', + '资兴' => ' zī xīng', + '分叉' => ' fēn chà', + '跪倒' => ' guì dǎo', + '跟头' => ' gēn tou', + '天雨' => ' tiān yù', + '分为' => ' fēn wéi', + '铣削' => ' xǐ xiāo', + '田子' => ' tián zǐ', + '摒绝' => ' bìng jué', + '臣仆' => ' chén pú', + '潦倒' => ' liáo dǎo', + '斗方' => ' dǒu fāng', + '橙子' => ' chéng zǐ', + '铅山' => ' yán shān', + '长图' => ' cháng tú', + '长股' => ' cháng gǔ', + '春假' => ' chūn jià', + '重覆' => ' chóng fù', + '重合' => ' chóng hé', + '重午' => ' chóng wǔ', + '发怔' => ' fā zhèng', + '斗拱' => ' dǒu gǒng', + '华山' => ' huà shān', + '长局' => ' cháng jú', + '重估' => ' chóng gū', + '长句' => ' cháng jù', + '页框' => ' yè kuàng', + '释卷' => ' shì juàn', + '丑角' => ' chǒu jué', + '醒豁' => ' xǐng huò', + '顶杆' => ' dǐng gǎn', + '顺差' => ' shùn chā', + '重启' => ' chóng qǐ', + '长嘶' => ' cháng sī', + '地转' => ' dì zhuàn', + '强迫' => ' qiǎng pò', + '长吁' => ' cháng xū', + '朝晖' => ' zhāo huī', + '潮差' => ' cháo chā', + '长足' => ' cháng zú', + '靓丽' => ' liàng lì', + '空缺' => ' kòng quē', + '长衣' => ' cháng yī', + '空难' => ' kōng nàn', + '打量' => ' dǎ liang', + '菌柄' => ' jùn bǐng', + '长须' => ' cháng xū', + '银行' => ' yín háng', + '扣应' => ' kòu yìng', + '昌都' => ' chāng dū', + '铺张' => ' pū zhāng', + '得中' => ' dé zhòng', + '尽兴' => ' jìn xìng', + '桦甸' => ' huà diàn', + '搀和' => ' chān huo', + '窨井' => ' yìn jǐng', + '销假' => ' xiāo jià', + '铣铁' => ' xiǎn tiě', + '强逼' => ' qiǎng bī', + '登载' => ' dēng zǎi', + '尽性' => ' jìn xìng', + '长丽' => ' cháng lì', + '时兴' => ' shí xīng', + '章子' => ' zhāng zǐ', + '重子' => ' zhòng zǐ', + '攀供' => ' pān gòng', + '冻干' => ' dòng gān', + '掷色' => ' zhì shǎi', + '拧开' => ' nǐng kāi', + '长路' => ' cháng lù', + '长利' => ' cháng lì', + '重提' => ' chóng tí', + '抄查' => ' chāo zhā', + '晕针' => ' yùn zhēn', + '长理' => ' cháng lǐ', + '白卷' => ' bái juàn', + '重屋' => ' chóng wū', + '暖和' => ' nuǎn huo', + '重沓' => ' chóng tà', + '应聘' => ' yìng pìn', + '冲压' => ' chòng yā', + '纶巾' => ' guān jīn', + '伎俩' => ' jì liǎng', + '重组' => ' chóng zǔ', + '弹跳' => ' tán tiào', + '竺乾' => ' zhú qián', + '强似' => ' qiáng sì', + '落枕' => ' lào zhěn', + '配称' => ' pèi chèn', + '酌处' => ' zhuó chǔ', + '长戟' => ' cháng jǐ', + '强拉' => ' qiǎng lā', + '强子' => ' qiáng zǐ', + '邓拓' => ' dèng tuò', + '长河' => ' cháng hé', + '落炕' => ' lào kàng', + '酬酢' => ' chóu zuò', + '技俩' => ' jì liǎng', + '横财' => ' hèng cái', + '重塑' => ' chóng sù', + '弹性' => ' tán xìng', + '场圃' => ' cháng pǔ', + '重复' => ' chóng fù', + '重荷' => ' zhòng hè', + '重聚' => ' chóng jù', + '菲酌' => ' fěi zhuó', + '自传' => ' zì zhuàn', + '螲蟷' => ' dié dāng', + '尽情' => ' jìn qíng', + '凋萎' => ' diāo wěi', + '估量' => ' gū liang', + '正子' => ' zhèng zǐ', + '正意' => ' zhēng yì', + '筠连' => ' jūn lián', + '岑参' => ' cén shēn', + '养分' => ' yǎng fèn', + '王著' => ' wáng zhù', + '撩开' => ' liáo kāi', + '撩逗' => ' liáo dòu', + '退还' => ' tuì huán', + '苍术' => ' cāng zhú', + '甲壳' => ' jiǎ qiào', + '查边' => ' zhā biān', + '甚微' => ' shèn wēi', + '甚或' => ' shèn huò', + '道观' => ' dào guàn', + '田舍' => ' tián shè', + '用处' => ' yòng chǔ', + '用尽' => ' yòng jìn', + '产假' => ' chǎn jià', + '产仔' => ' chǎn zǎi', + '生发' => ' shēng fà', + '欢势' => ' huān shi', + '正安' => ' zhēng an', + '这些' => ' zhèi xiē', + '道藏' => ' dào zàng', + '风头' => ' fēng tou', + '槛车' => ' jiàn chē', + '畹町' => ' wǎn dīng', + '都昌' => ' dū chāng', + '择菜' => ' zhái cài', + '颠茄' => ' diān qié', + '放倒' => ' fàng dǎo', + '答腔' => ' dā qiāng', + '甚且' => ' shèn qiě', + '着紧' => ' zháo jǐn', + '查检' => ' zhā jiǎn', + '饼干' => ' bǐng gān', + '着花' => ' zhuó huā', + '着落' => ' zhuó luò', + '连载' => ' lián zǎi', + '连累' => ' lián lěi', + '查岗' => ' zhā gǎng', + '腔子' => ' qiāng zǐ', + '废卷' => ' fèi juàn', + '通什' => ' tōng shí', + '年假' => ' nián jià', + '着处' => ' zhuó chù', + '道行' => ' dào héng', + '生子' => ' shēng zǐ', + '长驱' => ' cháng qū', + '盛器' => ' chéng qì', + '星宿' => ' xīng xiù', + '量计' => ' liáng jì', + '尽孝' => ' jìn xiào', + '横折' => ' héng shé', + '量测' => ' liáng cè', + '横暴' => ' hèng bào', + '橡子' => ' xiàng zǐ', + '华龙' => ' huà lóng', + '量度' => ' liáng dù', + '星斗' => ' xīng dǒu', + '电镐' => ' diàn hào', + '量子' => ' liàng zǐ', + '量器' => ' liáng qì', + '斗柄' => ' dǒu bǐng', + '皇子' => ' huáng zǐ', + '量具' => ' liáng jù', + '重译' => ' chóng yì', + '雕刀' => ' diāo dāo', + '刁斗' => ' diāo dǒu', + '立传' => ' lì zhuàn', + '横祸' => ' hèng huò', + '鞅牛' => ' yǎng níu', + '易传' => ' yì zhuàn', + '掺和' => ' chān huo', + '枪子' => ' qiāng zǐ', + '本行' => ' běn háng', + '甜头' => ' tián tou', + '显豁' => ' xiǎn huò', + '查照' => ' zhā zhào', + '风干' => ' fēng gān', + '曲江' => ' qǔ jiāng', + '游说' => ' yóu shuì', + '差人' => ' chāi rén', + '甚至' => ' shèn zhì', + '着然' => ' zhuó rán', + '找头' => ' zhǎo tou', + '年载' => ' nián zǎi', + '着眼' => ' zhuó yǎn', + '甚为' => ' shèn wéi', + '显著' => ' xiǎn zhù', + '空白' => ' kòng bái', + '落色' => ' lào shǎi', + '晒干' => ' shài gān', + '横切' => ' héng qiē', + '钓杆' => ' diào gǎn', + '长日' => ' cháng rì', + '解款' => ' jiè kuǎn', + '失调' => ' shī tiáo', + '引着' => ' yǐn zháo', + '应心' => ' yìng xīn', + '教给' => ' jiāo gěi', + '干笑' => ' gān xiào', + '丧假' => ' sāng jià', + '油坊' => ' yóu fáng', + '舍间' => ' shè jiān', + '耩子' => ' jiǎng zǐ', + '膙子' => ' jiǎng zǐ', + '应约' => ' yìng yuē', + '没空' => ' méi kòng', + '北漂' => ' běi piāo', + '家雀' => ' jiā qiǎo', + '甚佳' => ' shèn jiā', + '舍监' => ' shè jiān', + '应是' => ' yìng shì', + '奔命' => ' bèn mìng', + '应会' => ' yìng huì', + '应化' => ' yìng huà', + '神乐' => ' shén yuè', + '应给' => ' yìng gěi', + '单杠' => ' dān gàng', + '校改' => ' jiào gǎi', + '干俸' => ' gān fèng', + '藏蓝' => ' zàng lán', + '共处' => ' gòng chǔ', + '卜征' => ' bǔ zhēng', + '干瘦' => ' gān shòu', + '喧哗' => ' xuān huá', + '干癣' => ' gān xuǎn', + '好战' => ' hào zhàn', + '再兴' => ' zài xīng', + '榠楂' => ' míng chá', + '占卦' => ' zhān guà', + '侧歪' => ' zhāi wāi', + '斋舍' => ' zhāi shè', + '曾云' => ' zēng yún', + '藏民' => ' zàng mín', + '三省' => ' sān xǐng', + '曾加' => ' zēng jiā', + '桑干' => ' sāng gān', + '唤头' => ' huàn tou', + '曾华' => ' zēng huá', + '好氧' => ' hào yǎng', + '干冰' => ' gān bīng', + '乾坤' => ' qián kūn', + '黾勉' => ' mǐn miǎn', + '僧舍' => ' sēng shè', + '脚杆' => ' jiǎo gǎn', + '干等' => ' gān děng', + '好动' => ' hào dòng', + '调琴' => ' tiáo qín', + '勘校' => ' kān jiào', + '调处' => ' tiáo chǔ', + '挑担' => ' tiāo dàn', + '倾倒' => ' qīng dǎo', + '倾尽' => ' qīng jìn', + '报应' => ' bào yìng', + '捞着' => ' lāo zháo', + '僬侥' => ' jiāo yáo', + '刁难' => ' diāo nàn', + '文卷' => ' wén juàn', + '传记' => ' zhuàn jì', + '尾椎' => ' wěi zhuī', + '抗折' => ' kàng shé', + '为真' => ' wéi zhēn', + '咳喘' => ' ké chuǎn', + '允当' => ' yǔn dàng', + '外行' => ' wài háng', + '冰斗' => ' bīng dǒu', + '为性' => ' wéi xìng', + '报丧' => ' bào sāng', + '分行' => ' fēn háng', + '分当' => ' fèn dāng', + '兴筑' => ' xīng zhù', + '诱供' => ' yòu gòng', + '诱哄' => ' yòu hòng', + '二重' => ' èr chóng', + '渐染' => ' jiān rǎn', + '丧尸' => ' sāng shī', + '柬帖' => ' jiǎn tiě', + '卓著' => ' zhuó zhù', + '卒中' => ' cù zhòng', + '羽裳' => ' yǔ cháng', + '上齐' => ' shàng jì', + '了事' => ' liǎo shì', + '了却' => ' liǎo què', + '精尽' => ' jīng jìn', + '了结' => ' liǎo jié', + '夺冠' => ' duó guàn', + '少奶' => ' shào nǎi', + '了解' => ' liǎo jiě', + '有甚' => ' yǒu shèn', + '稍为' => ' shāo wéi', + '丧尽' => ' sàng jìn', + '有间' => ' yǒu jiàn', + '了然' => ' liǎo rán', + '塞翁' => ' sài wēng', + '协调' => ' xié tiáo', + '圜丘' => ' yuán qiū', + '失着' => ' shī zhāo', + '神煞' => ' shén shà', + '今朝' => ' jīn zhāo', + '勤朴' => ' qín piáo', + '胜似' => ' shèng sì', + '介壳' => ' jiè qiào', + '校注' => ' jiào zhù', + '甚者' => ' shèn zhě', + '动弹' => ' dòng tan', + '生得' => ' shēng de', + '什邡' => ' shí fāng', + '哗变' => ' huá biàn', + '解差' => ' jiè chāi', + '食甚' => ' shí shèn', + '巡更' => ' xún gēng', + '六行' => ' liù háng', + '舒卷' => ' shū juàn', + '雪糁' => ' xuě shēn', + '吓声' => ' hè shēng', + '天台' => ' tiān tāi', + '来朝' => ' lái zhāo', + '天分' => ' tiān fèn', + '悬瀑' => ' xuán bào', + '匀称' => ' yún chèn', + '勾当' => ' gòu dàng', + '供品' => ' gòng pǐn', + '一唱' => ' yí chàng', + '胜子' => ' shèng zǐ', + '掠阵' => ' lüě zhèn', + '嘉兴' => ' jiā xīng', + '解送' => ' jiè sòng', + '诗行' => ' shī háng', + '十行' => ' shí háng', + '劲草' => ' jìng cǎo', + '劲直' => ' jìng zhí', + '劲烈' => ' jìng liè', + '一长' => ' yī cháng', + '引吭' => ' yǐn háng', + '诗卷' => ' shī juàn', + '乱弹' => ' luàn tán', + '哗笑' => ' huá xiào', + '乘舆' => ' shèng yú', + '人参' => ' rén shēn', + '甚是' => ' shèn shì', + '娇娜' => ' jiāo nuó', + '呛咕' => ' qiāng gu', + '嚼头' => ' jiáo tóu', + '浇头' => ' jiāo tou', + '赎当' => ' shú dàng', + '惊倒' => ' jīng dǎo', + '园舍' => ' yuán shè', + '善处' => ' shàn chǔ', + '作坊' => ' zuō fang', + '作料' => ' zuó liào', + '遛鸟' => ' liù niǎo', + '作兴' => ' zuò xīng', + '龙湫' => ' lóng qiū', + '刷白' => ' shuà bái', + '漫卷' => ' màn juàn', + '焦干' => ' jiāo gān', + '晕圈' => ' yùn quān', + '佳兴' => ' jiā xīng', + '磟碡' => ' liù zhóu', + '干净' => ' gān jìng', + '苫盖' => ' shàn gài', + '嘉应' => ' jiā yìng', + '监本' => ' jiàn běn', + '干潮' => ' gān cháo', + '干煸' => ' gān biān', + '煞星' => ' shà xīng', + '乐段' => ' yuè duàn', + '丧事' => ' sāng shì', + '蒙事' => ' mēng shì', + '雁行' => ' yàn háng', + '掩卷' => ' yǎn juàn', + '数说' => ' shǔ shuō', + '佣金' => ' yòng jīn', + '数算' => ' shǔ suàn', + '圩场' => ' xū cháng', + '副相' => ' fù xiàng', + '供职' => ' gòng zhí', + '供花' => ' gòng huā', + '茎杆' => ' jīng gǎn', + '嚼舌' => ' jiáo shé', + '是甚' => ' shì shèn', + '天干' => ' tiān gān', + '佛像' => ' fó xiàng', + '尽欢' => ' jìn huān', + '劲射' => ' jìng shè', + '佛光' => ' fó guāng', + '嘲哳' => ' zhāo zhā', + '太监' => ' tài jiàn', + '路长' => ' lù cháng', + '龙仔' => ' lóng zǎi', + '加冠' => ' jiā guàn', + '洋镐' => ' yáng hào', + '尽让' => ' jìn ràng', + '收载' => ' shōu zǎi', + '边塞' => ' biān sài', + '失当' => ' shī dàng', + '抬杠' => ' tái gàng', + '收假' => ' shōu jià', + '刀削' => ' dāo xiāo', + '改行' => ' gǎi háng', + '斗筲' => ' dǒu shāo', + '倒找' => ' dǎo zhǎo', + '斗篷' => ' dǒu péng', + '长物' => ' cháng wù', + '微调' => ' wēi tiáo', + '长牙' => ' cháng yá', + '乐清' => ' yuè qīng', + '料斗' => ' liào dǒu', + '长途' => ' cháng tú', + '长武' => ' cháng wǔ', + '斜杠' => ' xié gàng', + '困觉' => ' kùn jiào', + '楞严' => ' lèng yán', + '瞒哄' => ' mán hǒng', + '数清' => ' shǔ qīng', + '称职' => ' chèn zhí', + '开钻' => ' kāi zuàn', + '杠头' => ' gàng tóu', + '零散' => ' líng sǎn', + '放假' => ' fàng jià', + '长笛' => ' cháng dí', + '扁担' => ' biǎn dàn', + '着火' => ' zháo huǒ', + '谁知' => ' shéi zhī', + '冠带' => ' guàn dài', + '冠绝' => ' guàn jué', + '馆舍' => ' guǎn shè', + '管乐' => ' guǎn yuè', + '水分' => ' shuǐ fèn', + '藤蔓' => ' téng wàn', + '调价' => ' tiáo jià', + '奖掖' => ' jiǎng yè', + '拉长' => ' lā cháng', + '倒算' => ' dǎo suàn', + '数点' => ' shǔ diǎn', + '倒剪' => ' dǎo jiǎn', + '瞓觉' => ' xùn jiào', + '教书' => ' jiāo shū', + '长袜' => ' cháng wà', + '倒卷' => ' dǎo juàn', + '长裤' => ' cháng kù', + '长葛' => ' cháng gě', + '倒嗓' => ' dǎo sǎng', + '兴仁' => ' xīng rén', + '知了' => ' zhī liǎo', + '开卷' => ' kāi juàn', + '刮削' => ' guā xiāo', + '露面' => ' lòu miàn', + '茸毛' => ' róng máo', + '草甸' => ' cǎo diàn', + '露脸' => ' lòu liǎn', + '的证' => ' dí zhèng', + '打场' => ' dǎ cháng', + '露苗' => ' lòu miáo', + '露丑' => ' lòu chǒu', + '相机' => ' xiàng jī', + '相扑' => ' xiàng pū', + '车削' => ' chē xiāo', + '支行' => ' zhī háng', + '镐京' => ' hào jīng', + '省察' => ' xǐng chá', + '露风' => ' lòu fēng', + '露馅' => ' lòu xiàn', + '空暇' => ' kòng xiá', + '等衰' => ' děng cuī', + '搅混' => ' jiǎo gǔn', + '撤差' => ' chè chāi', + '搅和' => ' jiǎo huo', + '相图' => ' xiàng tú', + '钻卡' => ' zuàn qiǎ', + '长乐' => ' cháng lè', + '散兵' => ' sǎn bīng', + '散乱' => ' sǎn luàn', + '当是' => ' dàng shì', + '思量' => ' sī liang', + '手弹' => ' shǒu tán', + '重播' => ' chóng bō', + '散件' => ' sǎn jiàn', + '乐团' => ' yuè tuán', + '蛏子' => ' chēng zǐ', + '闭上' => ' bì shang', + '倒产' => ' dǎo chǎn', + '倒垂' => ' dǎo chuí', + '称心' => ' chèn xīn', + '长发' => ' cháng fà', + '数念' => ' shǔ niàn', + '倒吊' => ' dǎo diào', + '长野' => ' cháng yě', + '长达' => ' cháng dá', + '倒动' => ' dǎo dòng', + '呈子' => ' chéng zǐ', + '倒风' => ' dǎo fēng', + '蒙牛' => ' měng níu', + '念头' => ' niàn tou', + '满拧' => ' mǎn nǐng', + '调侃' => ' tiáo kǎn', + '靓女' => ' liàng nǚ', + '羹匙' => ' gēng chí', + '变为' => ' biàn wéi', + '查拳' => ' zhā quán', + '议长' => ' yì cháng', + '挑唆' => ' tiǎo suō', + '未了' => ' wèi liǎo', + '藏人' => ' zàng rén', + '挑嘴' => ' tiǎo zuǐ', + '禀帖' => ' bǐng tiě', + '麻将' => ' má jiàng', + '藏文' => ' zàng wén', + '炮炼' => ' páo liàn', + '潦草' => ' liáo cǎo', + '更老' => ' gēng lǎo', + '黄埔' => ' huáng pǔ', + '圣子' => ' shèng zǐ', + '尿样' => ' suī yàng', + '黄陂' => ' huáng pō', + '澎湃' => ' péng pài', + '溃脓' => ' huì nóng', + '庚帖' => ' gēng tiě', + '请帖' => ' qǐng tiě', + '豁免' => ' huò miǎn', + '调频' => ' tiáo pín', + '请假' => ' qǐng jià', + '调谐' => ' tiáo xié', + '攻难' => ' gōng nàn', + '供事' => ' gòng shì', + '挑檐' => ' tiǎo yán', + '挑花' => ' tiǎo huā', + '着实' => ' zhuó shí', + '调音' => ' tiáo yīn', + '摒除' => ' bìng chú', + '调谑' => ' tiáo xuè', + '漫应' => ' màn yìng', + '调试' => ' tiáo shì', + '供饭' => ' gòng fàn', + '调训' => ' tiáo xùn', + '调解' => ' tiáo jiě', + '句芒' => ' gōu máng', + '挑逗' => ' tiǎo dòu', + '齿更' => ' chǐ gēng', + '挑衅' => ' tiǎo xìn', + '漂雷' => ' piāo léi', + '漂游' => ' piāo yóu', + '少尉' => ' shào wèi', + '够着' => ' gòu zháo', + '搂钱' => ' lōu qián', + '调驯' => ' tiáo xùn', + '对称' => ' duì chèn', + '漂白' => ' piǎo bái', + '记传' => ' jì zhuàn', + '讨还' => ' tǎo huán', + '缘分' => ' yuán fèn', + '搋子' => ' chuāi zǐ', + '处境' => ' chǔ jìng', + '评为' => ' píng wéi', + '龈病' => ' yín bìng', + '桄子' => ' guàng zǐ', + '挨整' => ' ái zhěng', + '调嘴' => ' tiáo zuǐ', + '安广' => ' ān guǎng', + '漂流' => ' piāo liú', + '调唆' => ' tiáo suō', + '固相' => ' gù xiàng', + '调味' => ' tiáo wèi', + '调协' => ' tiáo xié', + '调匀' => ' tiáo yún', + '漂染' => ' piǎo rǎn', + '漂摇' => ' piāo yáo', + '汤匙' => ' tāng chí', + '调制' => ' tiáo zhì', + '清查' => ' qīng zhā', + '宝应' => ' bǎo yìng', + '工尺' => ' gōng chě', + '滚杠' => ' gǔn gàng', + '冰瀑' => ' bīng bào', + '挺杆' => ' tǐng gǎn', + '调节' => ' tiáo jié', + '调摄' => ' tiáo shè', + '藓苔' => ' xiǎn tāi', + '将棋' => ' jiàng qí', + '将伯' => ' qiāng bó', + '虎将' => ' hǔ jiàng', + '测量' => ' cè liáng', + '该应' => ' gāi yìng', + '过甚' => ' guò shèn', + '臂长' => ' bì cháng', + '宝藏' => ' bǎo zàng', + '木框' => ' mù kuàng', + '涡阳' => ' guō yáng', + '试卷' => ' shì juàn', + '紧绷' => ' jǐn bēng', + '线杆' => ' xiàn gǎn', + '宝兴' => ' bǎo xīng', + '访查' => ' fǎng zhā', + '国丧' => ' guó sāng', + '相册' => ' xiàng cè', + '对应' => ' duì yìng', + '澄沙' => ' dèng shā', + '应验' => ' yìng yàn', + '碌碡' => ' liù zhou', + '应诺' => ' yìng nuò', + '恶创' => ' è chuāng', + '兴奋' => ' xīng fèn', + '情分' => ' qíng fèn', + '应运' => ' yìng yùn', + '程子' => ' chéng zǐ', + '芫花' => ' yuán huā', + '应门' => ' yìng mén', + '破相' => ' pò xiàng', + '攒射' => ' cuán shè', + '杠刀' => ' gàng dāo', + '大仓' => ' tài cāng', + '应邀' => ' yìng yāo', + '粉坊' => ' fěn fáng', + '排行' => ' pái háng', + '等为' => ' děng wéi', + '着恼' => ' zhuó nǎo', + '栏栅' => ' lán shān', + '还魂' => ' huán hún', + '画卷' => ' huà juàn', + '应试' => ' yìng shì', + '攒眉' => ' cuán méi', + '还给' => ' huán gěi', + '兴化' => ' xīng huà', + '冲模' => ' chòng mú', + '敌将' => ' dí jiàng', + '成都' => ' chéng dū', + '关塞' => ' guān sài', + '关卡' => ' guān qiǎ', + '悄然' => ' qiǎo rán', + '恰当' => ' qià dàng', + '称多' => ' chèn duō', + '大率' => ' dà shuài', + '阅卷' => ' yuè juàn', + '散工' => ' sǎn gōng', + '间谍' => ' jiàn dié', + '间歇' => ' jiàn xiē', + '杠杆' => ' gàng gǎn', + '间接' => ' jiàn jiē', + '间或' => ' jiàn huò', + '间奏' => ' jiàn zòu', + '种地' => ' zhòng dì', + '碎钻' => ' suì zuàn', + '患难' => ' huàn nàn', + '兴学' => ' xīng xué', + '还贷' => ' huán dài', + '钦差' => ' qīn chāi', + '花着' => ' huā zhāo', + '长法' => ' cháng fǎ', + '长骨' => ' cháng gǔ', + '折缝' => ' zhé féng', + '都城' => ' dū chéng', + '长歌' => ' cháng gē', + '邮差' => ' yóu chāi', + '督率' => ' dū shuài', + '长斧' => ' cháng fǔ', + '病假' => ' bìng jià', + '病倒' => ' bìng dǎo', + '敦朴' => ' dūn piáo', + '边卡' => ' biān qiǎ', + '折钱' => ' shé qián', + '张掖' => ' zhāng yè', + '著名' => ' zhù míng', + '弧长' => ' hú cháng', + '当晚' => ' dàng wǎn', + '朝来' => ' zhāo lái', + '当月' => ' dàng yuè', + '长辞' => ' cháng cí', + '折腾' => ' zhē téng', + '弦乐' => ' xián yuè', + '长鼓' => ' cháng gǔ', + '当做' => ' dàng zuò', + '还本' => ' huán běn', + '抽斗' => ' chōu dǒu', + '长策' => ' cháng cè', + '还书' => ' huán shū', + '抹胸' => ' mò xiōng', + '广安' => ' guǎng ān', + '厂子' => ' chǎng zǐ', + '当作' => ' dàng zuò', + '长波' => ' cháng bō', + '还口' => ' huán kǒu', + '还价' => ' huán jià', + '抽查' => ' chōu zhā', + '适应' => ' shì yìng', + '着数' => ' zhāo shù', + '留空' => ' liú kòng', + '频数' => ' pín shuò', + '筊杯' => ' jiǎo bēi', + '脑杓' => ' nǎo sháo', + '款新' => ' kuǎn xīn', + '击中' => ' jī zhòng', + '颠倒' => ' diān dǎo', + '适当' => ' shì dàng', + '还嘴' => ' huán zuǐ', + '成佛' => ' chéng fó', + '弄混' => ' nòng hún', + '兴国' => ' xīng guó', + '录相' => ' lù xiàng', + '省亲' => ' xǐng qīn', + '省视' => ' xǐng shì', + '长女' => ' cháng nǚ', + '长夜' => ' cháng yè', + '施甸' => ' shī diàn', + '支差' => ' zhī chāi', + '霓裳' => ' ní cháng', + '钻头' => ' zuàn tóu', + '茄萣' => ' qié dìng', + '房舍' => ' fáng shè', + '眄睐' => ' miàn lài', + '间作' => ' jiàn zuò', + '榔头' => ' láng tou', + '感应' => ' gǎn yìng', + '应接' => ' yìng jiē', + '只身' => ' zhī shēn', + '散见' => ' sǎn jiàn', + '般桓' => ' pán huán', + '舰只' => ' jiàn zhī', + '应时' => ' yìng shí', + '枕头' => ' zhěn tou', + '长子' => ' zhǎng zǐ', + '长安' => ' cháng ān', + '枕藉' => ' zhěn jiè', + '长于' => ' cháng yú', + '相似' => ' xiāng sì', + '自转' => ' zì zhuàn', + '荷重' => ' hè zhòng', + '椽子' => ' chuán zǐ', + '钻石' => ' zuàn shí', + '长椅' => ' cháng yǐ', + '空匮' => ' kòng kuì', + '看管' => ' kān guǎn', + '长期' => ' cháng qī', + '长揖' => ' cháng yī', + '打中' => ' dǎ zhòng', + '看守' => ' kān shǒu', + '长德' => ' cháng dé', + '长得' => ' zhǎng de', + '乐经' => ' yuè jīng', + '支应' => ' zhī yìng', + '长度' => ' cháng dù', + '新款' => ' xīn kuǎn', + '省得' => ' shěng de', + '新兴' => ' xīn xīng', + '长崎' => ' cháng qí', + '愁煞' => ' chóu shà', + '钻戒' => ' zuàn jiè', + '林甸' => ' lín diàn', + '杯筊' => ' bēi jiǎo', + '随行' => ' suí háng', + '应制' => ' yìng zhì', + '应分' => ' yīng fèn', + '松菌' => ' sōng jùn', + '兴办' => ' xīng bàn', + '应对' => ' yìng duì', + '兴头' => ' xìng tou', + '凭藉' => ' píng jiè', + '应市' => ' yìng shì', + '兴尽' => ' xìng jìn', + '应卯' => ' yìng mǎo', + '陡削' => ' dǒu xiāo', + '吹擂' => ' chuī lèi', + '降服' => ' xiáng fú', + '降伏' => ' xiáng fú', + '兴海' => ' xīng hǎi', + '吹弹' => ' chuī tán', + '应报' => ' yìng bào', + '雅相' => ' yǎ xiàng', + '闲散' => ' xián sǎn', + '色相' => ' sè xiàng', + '禁受' => ' jīn shòu', + '串子' => ' chuàn zǐ', + '阳萎' => ' yáng wěi', + '冲子' => ' chòng zi', + '碰倒' => ' pèng dǎo', + '槐荫' => ' huái yìn', + '兴文' => ' xīng wén', + '禁用' => ' jīn yòng', + '抽干' => ' chōu gān', + '应考' => ' yìng kǎo', + '腰椎' => ' yāo zhuī', + '散养' => ' sǎn yǎng', + '兴师' => ' xīng shī', + '爱将' => ' ài jiàng', + '锤头' => ' chuí tou', + '福相' => ' fú xiàng', + '榜笞' => ' bàng chī', + '色长' => ' sè cháng', + '禅位' => ' shàn wèi', + '处刑' => ' chǔ xíng', + '处斩' => ' chǔ zhǎn', + '慌得' => ' huāng de', + '兴宾' => ' xīng bīn', + '禾场' => ' hé cháng', + '糺' => ' jiū', + '糹' => ' sī', + '糼' => ' gōng', + '系' => ' xì', + '糾' => ' jiū', + '糷' => ' làn', + '糽' => ' zhěng', + '糸' => ' mì', + '糮' => ' xiàn', + '糶' => ' tiào', + '糵' => ' niè', + '糴' => ' dí', + '糳' => ' zuò', + '糲' => ' lì', + '糱' => ' niè', + '糰' => ' tuán', + '糯' => ' nuò', + '糭' => ' zòng', + '糬' => ' shu', + '糿' => ' yòu', + '糫' => ' huán', + '級' => ' jí', + '純' => ' chún', + '紀' => ' jì', + '紎' => ' zī', + '紘' => ' hóng', + '紗' => ' shā', + '紖' => ' zhèn', + '紕' => ' pī', + '糩' => ' kuài', + '紓' => ' shū', + '紒' => ' jì', + '紑' => ' fóu', + '紐' => ' niǔ', + '紏' => ' tǒu', + '納' => ' nà', + '紁' => ' chà', + '紌' => ' qiú', + '紋' => ' wén', + '紊' => ' wěn', + '紉' => ' rèn', + '紈' => ' wán', + '紇' => ' hé', + '紆' => ' yū', + '紅' => ' hóng', + '約' => ' yuē', + '紃' => ' xún', + '紂' => ' zhòu', + '糪' => ' bò', + '糒' => ' bèi', + '糨' => ' jiàng', + '糁' => ' sǎn', + '糋' => ' jiàn', + '糊' => ' hú', + '糉' => ' zòng', + '糈' => ' xǔ', + '糇' => ' hóu', + '糆' => ' miàn', + '糅' => ' róu', + '糄' => ' biǎn', + '糃' => ' táng', + '糂' => ' sǎn', + '粶' => ' lù', + '糍' => ' cí', + '糀' => ' hua', + '粿' => ' guǒ', + '精' => ' jīng', + '粽' => ' zòng', + '粷' => ' jú', + '粼' => ' lín', + '粻' => ' zhāng', + '粺' => ' bài', + '粹' => ' cuì', + '粸' => ' qí', + '糌' => ' zān', + '糎' => ' lí', + '糧' => ' liáng', + '糜' => ' mí', + '糦' => ' xī', + '糥' => ' nuò', + '糤' => ' sǎn', + '糣' => ' sǎn', + '糢' => ' mó', + '糡' => ' jiàng', + '糠' => ' kāng', + '糟' => ' zāo', + '糞' => ' fèn', + '糝' => ' sǎn', + '糛' => ' táng', + '糏' => ' xiè', + '糚' => ' zhuāng', + '糙' => ' cāo', + '糘' => ' jia', + '糗' => ' qiǔ', + '糖' => ' táng', + '糕' => ' gāo', + '糔' => ' xiǔ', + '糓' => ' gǔ', + '糑' => ' nuò', + '糐' => ' fū', + '紙' => ' zhǐ', + '絸' => ' jiǎn', + '紛' => ' fēn', + '絜' => ' jié', + '給' => ' gěi', + '絥' => ' fú', + '絤' => ' xiàn', + '絣' => ' bēng', + '絢' => ' xuàn', + '絡' => ' luò', + '絠' => ' gǎi', + '絟' => ' quán', + '絞' => ' jiǎo', + '絝' => ' kù', + '絛' => ' tāo', + '絨' => ' róng', + '絚' => ' gēng', + '絙' => ' huán', + '絘' => ' cì', + '絗' => ' hú', + '絖' => ' kuàng', + '絕' => ' jué', + '絔' => ' bǎi', + '絓' => ' guà', + '絒' => ' chóu', + '絑' => ' zhū', + '絧' => ' dòng', + '絩' => ' tiào', + '絏' => ' xiè', + '絶' => ' jué', + '絿' => ' qiú', + '粴' => ' lǐ', + '絾' => ' chéng', + '綀' => ' shū', + '絽' => ' lǚ', + '絼' => ' zhěn', + '絻' => ' miǎn', + '絺' => ' chī', + '絹' => ' juàn', + '絷' => ' zhí', + '絵' => ' huì', + '絪' => ' yīn', + '絴' => ' xiáng', + '絳' => ' jiàng', + '絲' => ' sī', + '統' => ' tǒng', + '絰' => ' dié', + '絯' => ' gāi', + '絮' => ' xù', + '絭' => ' juàn', + '絬' => ' xiè', + '絫' => ' lěi', + '結' => ' jié', + '絎' => ' háng', + '紜' => ' yún', + '紨' => ' fū', + '紲' => ' xiè', + '紱' => ' fú', + '細' => ' xì', + '累' => ' lèi', + '紮' => ' zā', + '紭' => ' hóng', + '紬' => ' chóu', + '紫' => ' zǐ', + '紪' => ' cǐ', + '紩' => ' zhì', + '紧' => ' jǐn', + '紴' => ' bō', + '紦' => ' ba', + '紥' => ' zā', + '紤' => ' jiǔ', + '紣' => ' cuì', + '索' => ' suǒ', + '紡' => ' fǎng', + '素' => ' sù', + '紟' => ' jīn', + '紞' => ' dǎn', + '紝' => ' rèn', + '紳' => ' shēn', + '紵' => ' zhù', + '絍' => ' rèn', + '終' => ' zhōng', + '経' => ' jīng', + '絋' => ' kuang', + '絊' => ' zuì', + '絉' => ' shù', + '絈' => ' mò', + '絇' => ' qú', + '絆' => ' bàn', + '絅' => ' jiōng', + '組' => ' zǔ', + '絃' => ' xián', + '絁' => ' shī', + '紶' => ' qū', + '絀' => ' chù', + '紿' => ' dài', + '紾' => ' zhěn', + '紽' => ' tuó', + '紼' => ' fú', + '紻' => ' yǎng', + '紺' => ' gàn', + '紹' => ' shào', + '紸' => ' zhù', + '紷' => ' líng', + '粵' => ' yuè', + '篱' => ' lí', + '粳' => ' jīng', + '簥' => ' jiāo', + '簯' => ' qi', + '簮' => ' zān', + '簭' => ' shì', + '簬' => ' lù', + '簫' => ' xiāo', + '簪' => ' zān', + '簩' => ' láo', + '簨' => ' sǔn', + '簧' => ' huáng', + '簦' => ' dēng', + '簤' => ' dài', + '簱' => ' qi', + '簣' => ' kuì', + '簢' => ' mǐn', + '簡' => ' jiǎn', + '簠' => ' fǔ', + '簟' => ' diàn', + '簞' => ' dān', + '簝' => ' liáo', + '簜' => ' dàng', + '簛' => ' shāi', + '簚' => ' mì', + '簰' => ' pái', + '簲' => ' pái', + '簘' => ' xiāo', + '簿' => ' bù', + '籉' => ' tái', + '籈' => ' zhēn', + '籇' => ' háo', + '籆' => ' yuè', + '籅' => ' yú', + '籄' => ' kuì', + '籃' => ' lán', + '籂' => ' shi', + '籁' => ' lài', + '籀' => ' zhòu', + '簾' => ' lián', + '簳' => ' gǎn', + '簽' => ' qiān', + '簼' => ' lóng', + '簻' => ' zhuā', + '簺' => ' sài', + '簹' => ' dāng', + '簸' => ' bǒ', + '簷' => ' yán', + '簶' => ' lù', + '簵' => ' dù', + '簴' => ' jù', + '簙' => ' bó', + '簗' => ' liang', + '籋' => ' niè', + '篰' => ' bù', + '篻' => ' piǎo', + '篺' => ' pí', + '篹' => ' zhuàn', + '篸' => ' cǎn', + '篷' => ' péng', + '篶' => ' yān', + '篵' => ' cōng', + '篴' => ' dí', + '篳' => ' bì', + '篲' => ' huì', + '篯' => ' jiān', + '篽' => ' yù', + '篮' => ' lán', + '篭' => ' lóng', + '篬' => ' qiāng', + '篫' => ' zhù', + '篪' => ' chí', + '篩' => ' shāi', + '篨' => ' chú', + '篦' => ' bì', + '綂' => ' tǒng', + '篧' => ' zhuó', + '篼' => ' dōu', + '篾' => ' miè', + '簖' => ' duàn', + '簋' => ' guǐ', + '簕' => ' lè', + '簔' => ' suō', + '簓' => ' diao', + '簒' => ' cuàn', + '簑' => ' suō', + '簐' => ' niǎn', + '簏' => ' lù', + '簎' => ' cè', + '簍' => ' lǒu', + '簌' => ' sù', + '簊' => ' jī', + '篿' => ' tuán', + '簉' => ' zào', + '簈' => ' píng', + '簇' => ' cù', + '簆' => ' kòu', + '簅' => ' chǎn', + '簄' => ' hù', + '簃' => ' yí', + '簂' => ' guì', + '簁' => ' shāi', + '簀' => ' zé', + '籊' => ' tì', + '籌' => ' chóu', + '粲' => ' càn', + '粍' => ' zhé', + '粗' => ' cū', + '粖' => ' mò', + '粕' => ' pò', + '粔' => ' jù', + '粓' => ' gān', + '粒' => ' lì', + '粑' => ' bā', + '粐' => ' hu', + '粏' => ' tai', + '粎' => ' chǐ', + '粌' => ' yin', + '粙' => ' zhòu', + '粋' => ' cuì', + '粊' => ' bì', + '粉' => ' fěn', + '粈' => ' rǒu', + '粇' => ' kāng', + '粆' => ' shā', + '粅' => ' wù', + '粄' => ' bǎn', + '粃' => ' bǐ', + '粂' => ' zhai', + '粘' => ' zhān', + '粚' => ' lí', + '粀' => ' zhang', + '粧' => ' zhuāng', + '粱' => ' liáng', + '粰' => ' fú', + '粯' => ' xiàn', + '粮' => ' liáng', + '粭' => ' he', + '粬' => ' qū', + '粫' => ' ér', + '粪' => ' fèn', + '粩' => ' lao', + '粨' => ' bǎi', + '粦' => ' lín', + '粛' => ' sù', + '粥' => ' zhōu', + '粤' => ' yuè', + '粣' => ' cè', + '粢' => ' zī', + '粡' => ' tóng', + '粠' => ' hóng', + '粟' => ' sù', + '粞' => ' xī', + '粝' => ' lì', + '粜' => ' tiào', + '粁' => ' qiān', + '籿' => ' cùn', + '籍' => ' jí', + '籙' => ' lù', + '籣' => ' lán', + '籢' => ' lián', + '籡' => ' qie', + '籠' => ' lóng', + '籟' => ' lài', + '籞' => ' yù', + '籝' => ' yíng', + '籜' => ' tuò', + '籛' => ' jiǎn', + '籚' => ' lú', + '籘' => ' téng', + '籥' => ' yuè', + '籗' => ' zhuó', + '籖' => ' qian', + '籕' => ' zhòu', + '籔' => ' sǒu', + '籓' => ' fān', + '籒' => ' zhòu', + '籑' => ' zhuàn', + '籐' => ' téng', + '籏' => ' qi', + '籎' => ' yi', + '籤' => ' qiān', + '籦' => ' zhōng', + '籾' => ' ní', + '米' => ' mǐ', + '籽' => ' zǐ', + '籼' => ' xiān', + '类' => ' lèi', + '籺' => ' hé', + '籹' => ' nǚ', + '籸' => ' shēn', + '籷' => ' zhé', + '籶' => ' shēn', + '籵' => ' fán', + '籴' => ' dí', + '籲' => ' yù', + '籧' => ' qú', + '籱' => ' zhuó', + '籰' => ' yuè', + '籯' => ' yíng', + '籮' => ' luó', + '籭' => ' sī', + '籬' => ' lí', + '籫' => ' zuǎn', + '籪' => ' duàn', + '籩' => ' biān', + '籨' => ' lián', + '綁' => ' bǎng', + '缎' => ' duàn', + '綃' => ' xiāo', + '纔' => ' cái', + '纞' => ' liàn', + '纝' => ' léi', + '纜' => ' lǎn', + '纛' => ' dào', + '纚' => ' lí', + '纙' => ' luò', + '纘' => ' zuǎn', + '纗' => ' zuī', + '纖' => ' xiān', + '纕' => ' rǎng', + '纓' => ' yīng', + '纠' => ' jiū', + '纒' => ' chán', + '纑' => ' lú', + '纐' => ' jiao', + '纏' => ' chán', + '纎' => ' xiān', + '纍' => ' léi', + '續' => ' xù', + '纋' => ' yōu', + '纊' => ' kuàng', + '纉' => ' zuǎn', + '纟' => ' sī', + '纡' => ' yū', + '纇' => ' lèi', + '纮' => ' hóng', + '纸' => ' zhǐ', + '纷' => ' fēn', + '纶' => ' lún', + '纵' => ' zòng', + '纴' => ' rèn', + '纳' => ' nà', + '纲' => ' gāng', + '纱' => ' shā', + '纰' => ' pī', + '纯' => ' chún', + '纭' => ' yún', + '红' => ' hóng', + '纬' => ' wěi', + '纫' => ' rèn', + '纪' => ' jì', + '纩' => ' kuàng', + '纨' => ' wán', + '级' => ' jí', + '约' => ' yuē', + '纥' => ' gē', + '纤' => ' xiān', + '纣' => ' zhòu', + '纈' => ' xié', + '纆' => ' mò', + '纺' => ' fǎng', + '繠' => ' ruǐ', + '繪' => ' huì', + '繩' => ' shéng', + '繨' => ' da', + '繧' => ' yun', + '繦' => ' qiǎng', + '繥' => ' xī', + '繤' => ' zuǎn', + '繣' => ' huà', + '繢' => ' huì', + '繡' => ' xiù', + '繟' => ' chǎn', + '繬' => ' sè', + '繞' => ' rào', + '繝' => ' jiàn', + '繜' => ' zūn', + '繛' => ' chuò', + '繚' => ' liáo', + '繙' => ' fān', + '繘' => ' yù', + '繗' => ' lín', + '繖' => ' sǎn', + '繕' => ' shàn', + '繫' => ' xì', + '繭' => ' jiǎn', + '纅' => ' yào', + '繺' => ' shǎi', + '纄' => ' péng', + '纃' => ' qí', + '纂' => ' zuǎn', + '纁' => ' xūn', + '纀' => ' pú', + '繿' => ' lán', + '繾' => ' qiǎn', + '繽' => ' bīn', + '繼' => ' jì', + '繻' => ' xū', + '繹' => ' yì', + '繮' => ' jiāng', + '繸' => ' suì', + '繷' => ' nǒng', + '繶' => ' yì', + '繵' => ' dàn', + '繴' => ' bì', + '繳' => ' jiǎo', + '繲' => ' xiè', + '繱' => ' cōng', + '繰' => ' zǎo', + '繯' => ' huán', + '纹' => ' wén', + '纻' => ' zhù', + '繓' => ' zuǒ', + '综' => ' zōng', + '缆' => ' lǎn', + '缅' => ' miǎn', + '缄' => ' jiān', + '缃' => ' xiāng', + '缂' => ' kè', + '缁' => ' zī', + '缀' => ' zhuì', + '绿' => ' lǜ', + '绾' => ' wǎn', + '绽' => ' zhàn', + '绻' => ' quǎn', + '缈' => ' miǎo', + '绺' => ' liǔ', + '绹' => ' táo', + '绸' => ' chóu', + '绷' => ' běng', + '绶' => ' shòu', + '绵' => ' mián', + '维' => ' wéi', + '绳' => ' shéng', + '绲' => ' gǔn', + '绱' => ' shàng', + '缇' => ' tí', + '缉' => ' jī', + '绯' => ' fēi', + '缗' => ' mín', + '缠' => ' chán', + '篤' => ' dǔ', + '缟' => ' gǎo', + '缞' => ' cuī', + '缝' => ' fèng', + '缜' => ' zhěn', + '缛' => ' rù', + '缚' => ' fù', + '缙' => ' jìn', + '缘' => ' yuán', + '编' => ' biān', + '缊' => ' yūn', + '缕' => ' lǚ', + '缔' => ' dì', + '缓' => ' huǎn', + '缒' => ' zhuì', + '缑' => ' gōu', + '缐' => ' xiàn', + '缏' => ' biàn', + '缍' => ' duǒ', + '缌' => ' sī', + '缋' => ' huì', + '绰' => ' chuò', + '绮' => ' qǐ', + '纼' => ' zhèn', + '终' => ' zhōng', + '绒' => ' róng', + '绑' => ' bǎng', + '绐' => ' dài', + '经' => ' jīng', + '绎' => ' yì', + '绍' => ' shào', + '绌' => ' chù', + '绋' => ' fú', + '绊' => ' bàn', + '绉' => ' zhòu', + '织' => ' zhī', + '绔' => ' kù', + '细' => ' xì', + '绅' => ' shēn', + '组' => ' zǔ', + '练' => ' liàn', + '绂' => ' fú', + '绁' => ' xiè', + '绀' => ' gàn', + '线' => ' xiàn', + '纾' => ' shū', + '纽' => ' niǔ', + '结' => ' jié', + '绕' => ' rào', + '续' => ' xù', + '绢' => ' juàn', + '绬' => ' yīng', + '绫' => ' líng', + '绪' => ' xù', +); diff --git a/lib/vendor/overtrue/pinyin/data/words_2 b/lib/vendor/overtrue/pinyin/data/words_2 new file mode 100644 index 0000000000..7cd17fec83 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_2 @@ -0,0 +1,8003 @@ + ' jī', + '绨' => ' tí', + '继' => ' jì', + '绦' => ' tāo', + '绥' => ' suí', + '绤' => ' xì', + '绣' => ' xiù', + '绡' => ' xiāo', + '绖' => ' dié', + '绠' => ' gěng', + '统' => ' tǒng', + '绞' => ' jiǎo', + '绝' => ' jué', + '络' => ' luò', + '绛' => ' jiàng', + '绚' => ' xuàn', + '给' => ' gěi', + '绘' => ' huì', + '绗' => ' háng', + '織' => ' zhī', + '繒' => ' zēng', + '綄' => ' huán', + '緄' => ' gǔn', + '緎' => ' yù', + '緍' => ' mín', + '緌' => ' ruí', + '緋' => ' fēi', + '緊' => ' jǐn', + '緉' => ' liǎng', + '緈' => ' xìng', + '緇' => ' zī', + '緆' => ' xī', + '緅' => ' zōu', + '緃' => ' zōng', + '緐' => ' fán', + '緂' => ' tián', + '緁' => ' qiè', + '緀' => ' qī', + '綿' => ' mián', + '綾' => ' líng', + '綽' => ' chuò', + '綼' => ' bì', + '綻' => ' zhàn', + '綺' => ' qǐ', + '綹' => ' liǔ', + '総' => ' zǒng', + '緑' => ' lǜ', + '綷' => ' cuì', + '緞' => ' duàn', + '編' => ' biān', + '緧' => ' qiū', + '緦' => ' sī', + '緥' => ' bǎo', + '緤' => ' xiè', + '緣' => ' yuán', + '緢' => ' miáo', + '緡' => ' mín', + '締' => ' dì', + '緟' => ' chóng', + '緝' => ' jī', + '緒' => ' xù', + '緜' => ' mián', + '緛' => ' ruǎn', + '線' => ' xiàn', + '緙' => ' kè', + '緘' => ' jiān', + '緗' => ' xiāng', + '緖' => ' xù', + '緕' => ' qi', + '緔' => ' shàng', + '緓' => ' yīng', + '綸' => ' lún', + '綶' => ' guǒ', + '緪' => ' gēng', + '綐' => ' duì', + '続' => ' xu', + '継' => ' jì', + '綘' => ' féng', + '綗' => ' jiǒng', + '綖' => ' yán', + '綕' => ' zhī', + '綔' => ' hù', + '經' => ' jīng', + '綒' => ' fū', + '綑' => ' kǔn', + '綏' => ' suī', + '綜' => ' zōng', + '綎' => ' tīng', + '綍' => ' fú', + '綌' => ' xì', + '綋' => ' hóng', + '綊' => ' xié', + '綉' => ' tòu', + '綈' => ' tí', + '綇' => ' xiǔ', + '綆' => ' gěng', + '綅' => ' qīn', + '綛' => ' ren', + '綝' => ' chēn', + '綵' => ' cǎi', + '綪' => ' qiàn', + '綴' => ' zhuì', + '綳' => ' bēng', + '網' => ' wǎng', + '綱' => ' gāng', + '綰' => ' wǎn', + '綯' => ' táo', + '綮' => ' qǐ', + '維' => ' wéi', + '綬' => ' shòu', + '綫' => ' xiàn', + '綩' => ' wǎn', + '綞' => ' duǒ', + '綨' => ' qí', + '綧' => ' zhǔn', + '綦' => ' qí', + '綥' => ' qí', + '綤' => ' shào', + '綣' => ' quǎn', + '綢' => ' chóu', + '綡' => ' liáng', + '綠' => ' lǜ', + '綟' => ' lì', + '緩' => ' huǎn', + '緫' => ' cōng', + '繑' => ' qiāo', + '縬' => ' cù', + '縶' => ' zhí', + '縵' => ' màn', + '縴' => ' qiàn', + '縳' => ' juàn', + '縲' => ' léi', + '縱' => ' zòng', + '縰' => ' xǐ', + '縯' => ' yǎn', + '縮' => ' suō', + '縭' => ' lí', + '縫' => ' fèng', + '縸' => ' mù', + '縪' => ' bì', + '縩' => ' cài', + '縨' => ' huang', + '縧' => ' tāo', + '縦' => ' zòng', + '縥' => ' zhěn', + '縤' => ' sù', + '縣' => ' xiàn', + '縢' => ' téng', + '縡' => ' zài', + '縷' => ' lǚ', + '縹' => ' piǎo', + '縟' => ' rù', + '繆' => ' móu', + '繐' => ' suì', + '繏' => ' xuàn', + '繎' => ' rán', + '繍' => ' xiù', + '繌' => ' sha', + '繋' => ' jì', + '繊' => ' xian', + '繉' => ' hún', + '繈' => ' qiǎng', + '繇' => ' yáo', + '繅' => ' sāo', + '縺' => ' lián', + '繄' => ' yī', + '繃' => ' běng', + '繂' => ' lǜ', + '繁' => ' fán', + '繀' => ' suì', + '縿' => ' shān', + '績' => ' jī', + '總' => ' zǒng', + '縼' => ' xuàn', + '縻' => ' mí', + '縠' => ' hú', + '縞' => ' gǎo', + '緬' => ' miǎn', + '緸' => ' yīn', + '縂' => ' zǒng', + '縁' => ' yuán', + '縀' => ' xiá', + '緿' => ' dài', + '緾' => ' chán', + '緽' => ' chēng', + '緼' => ' yùn', + '緻' => ' zhì', + '緺' => ' guā', + '緹' => ' tí', + '緷' => ' yùn', + '縄' => ' ying', + '緶' => ' biàn', + '緵' => ' zōng', + '練' => ' liàn', + '緳' => ' xié', + '緲' => ' miǎo', + '緱' => ' gōu', + '緰' => ' tóu', + '緯' => ' wěi', + '緮' => ' fù', + '緭' => ' wèi', + '縃' => ' xū', + '縅' => ' wei', + '縝' => ' chēn', + '縒' => ' cī', + '縜' => ' yún', + '縛' => ' fù', + '縚' => ' tāo', + '縙' => ' róng', + '縘' => ' xī', + '縗' => ' cuī', + '縖' => ' xiá', + '縕' => ' yūn', + '縔' => ' shuǎng', + '縓' => ' quán', + '縑' => ' jiān', + '縆' => ' gēng', + '縐' => ' zhòu', + '縏' => ' pán', + '縎' => ' gǔ', + '縍' => ' bāng', + '縌' => ' nì', + '縋' => ' zhuì', + '縊' => ' yì', + '縉' => ' jìn', + '縈' => ' yíng', + '縇' => ' xuān', + '篥' => ' lì', + '磇' => ' pī', + '篣' => ' péng', + '禴' => ' yuè', + '禾' => ' hé', + '禽' => ' qín', + '禼' => ' xiè', + '离' => ' lí', + '禺' => ' yú', + '禹' => ' yǔ', + '禸' => ' róu', + '禷' => ' lèi', + '禶' => ' zàn', + '禵' => ' tí', + '禳' => ' ráng', + '秀' => ' xiù', + '禲' => ' lì', + '禱' => ' dǎo', + '禰' => ' mí', + '禯' => ' nóng', + '禮' => ' lǐ', + '禭' => ' suì', + '禬' => ' guì', + '禫' => ' dàn', + '禪' => ' chán', + '禩' => ' sì', + '禿' => ' tū', + '私' => ' sī', + '禧' => ' xǐ', + '秎' => ' fèn', + '秘' => ' mì', + '秗' => ' yù', + '秖' => ' zhī', + '秕' => ' bǐ', + '秔' => ' jīng', + '秓' => ' zhī', + '秒' => ' miǎo', + '科' => ' kē', + '秐' => ' yún', + '秏' => ' hào', + '种' => ' zhǒng', + '秂' => ' rén', + '秌' => ' qiū', + '秋' => ' qiū', + '秊' => ' nián', + '秉' => ' bǐng', + '秈' => ' xiān', + '秇' => ' yì', + '秆' => ' gǎn', + '秅' => ' chá', + '秄' => ' zǐ', + '秃' => ' tū', + '禨' => ' jī', + '禦' => ' yù', + '秚' => ' bàn', + '禀' => ' bǐng', + '禊' => ' xì', + '禉' => ' yǒu', + '禈' => ' huī', + '禇' => ' zhě', + '禆' => ' bēi', + '禅' => ' chán', + '禄' => ' lù', + '禃' => ' zhí', + '禂' => ' dǎo', + '禁' => ' jìn', + '祿' => ' lù', + '禌' => ' zī', + '祾' => ' líng', + '祽' => ' zuì', + '祼' => ' guàn', + '祻' => ' gù', + '祺' => ' qí', + '祹' => ' táo', + '祸' => ' huò', + '祷' => ' dǎo', + '祶' => ' dì', + '祵' => ' kǔn', + '禋' => ' yīn', + '禍' => ' huò', + '禥' => ' qí', + '禚' => ' zhuó', + '禤' => ' xuān', + '禣' => ' fu', + '禢' => ' tà', + '禡' => ' mà', + '禠' => ' sī', + '禟' => ' táng', + '禞' => ' gào', + '禝' => ' jí', + '禜' => ' yǒng', + '禛' => ' zhēn', + '禙' => ' bei', + '禎' => ' zhēn', + '禘' => ' dì', + '禗' => ' sī', + '禖' => ' méi', + '禕' => ' yī', + '禔' => ' zhī', + '禓' => ' yáng', + '禒' => ' xiǎn', + '禑' => ' wú', + '禐' => ' yuàn', + '福' => ' fú', + '秙' => ' kù', + '秛' => ' pī', + '祳' => ' shèn', + '稜' => ' léng', + '稦' => ' yī', + '稥' => ' xiāng', + '稤' => ' lüè', + '稣' => ' sū', + '稢' => ' yù', + '稡' => ' zuì', + '稠' => ' chóu', + '稟' => ' bǐng', + '稞' => ' kē', + '稝' => ' péng', + '稛' => ' kǔn', + '稨' => ' biǎn', + '稚' => ' zhì', + '稙' => ' zhī', + '稘' => ' jī', + '稗' => ' bài', + '稖' => ' bàng', + '稕' => ' zhùn', + '稔' => ' rěn', + '稓' => ' zuó', + '稒' => ' gù', + '稑' => ' lù', + '稧' => ' xì', + '稩' => ' jì', + '稏' => ' yà', + '稶' => ' yù', + '穀' => ' gǔ', + '稿' => ' gǎo', + '稾' => ' gǎo', + '稽' => ' jī', + '稼' => ' jià', + '稻' => ' dào', + '稺' => ' zhì', + '稹' => ' zhěn', + '稸' => ' xù', + '稷' => ' jì', + '稵' => ' zī', + '稪' => ' fú', + '稴' => ' xián', + '稳' => ' wěn', + '稲' => ' dào', + '稱' => ' chēng', + '稰' => ' xǔ', + '稯' => ' zōng', + '種' => ' zhǒng', + '稭' => ' jiē', + '稬' => ' nuò', + '稫' => ' pì', + '稐' => ' lǔn', + '税' => ' shuì', + '秜' => ' ní', + '秨' => ' zuó', + '秲' => ' zhì', + '秱' => ' tóng', + '称' => ' chēng', + '积' => ' jī', + '秮' => ' huó', + '秭' => ' zǐ', + '秬' => ' jù', + '秫' => ' shú', + '秪' => ' zhī', + '秩' => ' zhì', + '秧' => ' yāng', + '秴' => ' hé', + '秦' => ' qín', + '秥' => ' nián', + '秤' => ' chèng', + '秣' => ' mò', + '秢' => ' líng', + '秡' => ' bó', + '秠' => ' pī', + '租' => ' zū', + '秞' => ' yóu', + '秝' => ' lì', + '秳' => ' huó', + '秵' => ' yīn', + '稍' => ' shāo', + '稂' => ' láng', + '稌' => ' tú', + '程' => ' chéng', + '稊' => ' tí', + '稉' => ' jīng', + '稈' => ' gǎn', + '稇' => ' kǔn', + '稆' => ' lǚ', + '稅' => ' shuì', + '稄' => ' xùn', + '稃' => ' fū', + '稁' => ' kǎo', + '秶' => ' zī', + '稀' => ' xī', + '秿' => ' fù', + '秾' => ' nóng', + '秽' => ' huì', + '秼' => ' zhū', + '移' => ' yí', + '秺' => ' dù', + '秹' => ' rěn', + '秸' => ' jiē', + '秷' => ' zhì', + '祴' => ' gāi', + '祲' => ' jìn', + '穂' => ' suì', + '磤' => ' yǐn', + '磮' => ' lun', + '磭' => ' chuò', + '磬' => ' qìng', + '磫' => ' zōng', + '磪' => ' cuī', + '磩' => ' qì', + '磨' => ' mó', + '磧' => ' qì', + '磦' => ' biāo', + '磥' => ' lěi', + '磣' => ' chěn', + '磰' => ' shàn', + '磢' => ' chuǎng', + '磡' => ' kàn', + '磠' => ' lǔ', + '磟' => ' liù', + '磞' => ' pēng', + '磝' => ' áo', + '磜' => ' qì', + '磛' => ' chán', + '磚' => ' zhuān', + '磙' => ' gǔn', + '磯' => ' jī', + '磱' => ' láo', + '磗' => ' zhuān', + '磾' => ' dī', + '礈' => ' zhuì', + '礇' => ' yù', + '礆' => ' jiǎn', + '礅' => ' dūn', + '礄' => ' qiáo', + '礃' => ' zhǎng', + '礂' => ' xi', + '礁' => ' jiāo', + '礀' => ' jian', + '磿' => ' lì', + '磽' => ' qiāo', + '磲' => ' qú', + '磼' => ' zá', + '磻' => ' pán', + '磺' => ' huáng', + '磹' => ' tán', + '磸' => ' dìng', + '磷' => ' lín', + '磶' => ' xì', + '磵' => ' jiàn', + '磴' => ' dèng', + '磳' => ' zēng', + '磘' => ' qìng', + '磖' => ' lá', + '礊' => ' kè', + '碯' => ' nǎo', + '碹' => ' xuàn', + '碸' => ' fēng', + '碷' => ' dun', + '碶' => ' qì', + '碵' => ' tian', + '碴' => ' chá', + '碳' => ' tàn', + '碲' => ' dì', + '碱' => ' jiǎn', + '碰' => ' pèng', + '碮' => ' tí', + '碻' => ' què', + '碭' => ' dàng', + '碬' => ' xiá', + '碫' => ' duàn', + '碪' => ' zhēn', + '碩' => ' shuò', + '碨' => ' wèi', + '碧' => ' bì', + '碦' => ' kè', + '碥' => ' biǎn', + '缢' => ' yì', + '確' => ' què', + '碼' => ' mǎ', + '磕' => ' kē', + '磊' => ' lěi', + '磔' => ' zhé', + '磓' => ' duī', + '磒' => ' yǔn', + '磑' => ' wéi', + '磐' => ' pán', + '磏' => ' lián', + '磎' => ' xī', + '磍' => ' xiá', + '磌' => ' tián', + '磋' => ' cuō', + '磉' => ' sǎng', + '碽' => ' gōng', + '磈' => ' wěi', + '磆' => ' huá', + '磅' => ' bàng', + '磄' => ' táng', + '磃' => ' sī', + '磂' => ' liú', + '磁' => ' cí', + '磀' => ' é', + '碿' => ' sù', + '碾' => ' niǎn', + '礉' => ' hé', + '礋' => ' zé', + '祱' => ' shuì', + '祌' => ' zhòng', + '祖' => ' zǔ', + '祕' => ' mì', + '祔' => ' fù', + '祓' => ' fú', + '祒' => ' tiáo', + '祑' => ' zhì', + '祐' => ' yòu', + '祏' => ' shí', + '祎' => ' yī', + '祍' => ' rèn', + '祋' => ' duì', + '祘' => ' suàn', + '祊' => ' bēng', + '祉' => ' zhǐ', + '祈' => ' qí', + '祇' => ' qí', + '祆' => ' xiān', + '祅' => ' yāo', + '祄' => ' xiè', + '祃' => ' mà', + '祂' => ' tā', + '祁' => ' qí', + '祗' => ' zhī', + '祙' => ' mèi', + '礿' => ' yuè', + '祦' => ' wú', + '祰' => ' gào', + '祯' => ' zhēn', + '祮' => ' gào', + '祭' => ' jì', + '祬' => ' zhī', + '祫' => ' xiá', + '祪' => ' guǐ', + '祩' => ' zhù', + '票' => ' piào', + '祧' => ' tiāo', + '祥' => ' xiáng', + '祚' => ' zuò', + '祤' => ' yǔ', + '祣' => ' lǚ', + '祢' => ' mí', + '祡' => ' chái', + '祠' => ' cí', + '祟' => ' suì', + '神' => ' shén', + '祝' => ' zhù', + '祜' => ' hù', + '祛' => ' qū', + '祀' => ' sì', + '社' => ' shè', + '礌' => ' léi', + '礘' => ' è', + '礢' => ' yang', + '礡' => ' bó', + '礠' => ' cí', + '礟' => ' pào', + '礞' => ' méng', + '礝' => ' ruǎn', + '礜' => ' yù', + '礛' => ' jiān', + '礚' => ' kē', + '礙' => ' ài', + '礗' => ' pīn', + '礤' => ' cǎ', + '礖' => ' yù', + '礕' => ' pī', + '礔' => ' pī', + '礓' => ' jiāng', + '礒' => ' yǐ', + '礑' => ' dàng', + '礐' => ' què', + '礏' => ' yè', + '礎' => ' chǔ', + '礍' => ' kě', + '礣' => ' mà', + '礥' => ' xián', + '礽' => ' réng', + '礲' => ' lóng', + '礼' => ' lǐ', + '礻' => ' shì', + '示' => ' shì', + '礹' => ' yán', + '礸' => ' zǎn', + '礷' => ' lán', + '礶' => ' guàn', + '礵' => ' shuāng', + '礴' => ' bó', + '礳' => ' mò', + '礱' => ' lóng', + '礦' => ' kuàng', + '礰' => ' lì', + '礯' => ' yīng', + '礮' => ' pào', + '礭' => ' què', + '礬' => ' fán', + '礫' => ' lì', + '礪' => ' lì', + '礩' => ' zhì', + '礨' => ' lěi', + '礧' => ' léi', + '穁' => ' róng', + '穃' => ' rong', + '篢' => ' lǒng', + '筕' => ' háng', + '筟' => ' fū', + '筞' => ' cè', + '筝' => ' zhēng', + '筜' => ' dāng', + '筛' => ' shāi', + '筚' => ' bì', + '筙' => ' lái', + '筘' => ' kòu', + '筗' => ' zhòng', + '策' => ' cè', + '答' => ' dá', + '筡' => ' tú', + '筓' => ' jī', + '筒' => ' tǒng', + '筑' => ' zhù', + '筐' => ' kuāng', + '筏' => ' fá', + '筎' => ' rú', + '筍' => ' sǔn', + '筌' => ' quán', + '筋' => ' jīn', + '筊' => ' xiáo', + '筠' => ' yún', + '筢' => ' pá', + '筈' => ' kuò', + '筯' => ' zhù', + '筹' => ' chóu', + '筸' => ' gān', + '筷' => ' kuài', + '筶' => ' gào', + '筵' => ' yán', + '筴' => ' cè', + '筳' => ' tíng', + '筲' => ' shāo', + '筱' => ' xiǎo', + '筰' => ' zuó', + '筮' => ' shì', + '筣' => ' lí', + '筭' => ' suàn', + '筬' => ' chéng', + '筫' => ' zhì', + '筪' => ' xiá', + '筩' => ' tóng', + '筨' => ' hán', + '筧' => ' jiǎn', + '筦' => ' guǎn', + '筥' => ' jǔ', + '筤' => ' láng', + '等' => ' děng', + '筇' => ' qióng', + '筻' => ' gàng', + '笡' => ' qiè', + '笫' => ' zǐ', + '笪' => ' dá', + '笩' => ' pèi', + '笨' => ' bèn', + '笧' => ' cè', + '符' => ' fú', + '笥' => ' sì', + '笤' => ' tiáo', + '笣' => ' bāo', + '笢' => ' mǐn', + '笠' => ' lì', + '笭' => ' líng', + '笟' => ' gū', + '笞' => ' chī', + '笝' => ' nà', + '笜' => ' zhú', + '笛' => ' dí', + '笚' => ' dā', + '笙' => ' shēng', + '笘' => ' shān', + '笗' => ' dōng', + '笖' => ' yǐ', + '第' => ' dì', + '笮' => ' zé', + '筆' => ' bǐ', + '笻' => ' qióng', + '筅' => ' xiǎn', + '筄' => ' yào', + '筃' => ' yīn', + '筂' => ' chí', + '筁' => ' qū', + '筀' => ' guì', + '笿' => ' luò', + '笾' => ' biān', + '笽' => ' min', + '笼' => ' lóng', + '笺' => ' jiān', + '笯' => ' nú', + '笹' => ' ti', + '笸' => ' pǒ', + '笷' => ' mǎo', + '笶' => ' shǐ', + '笵' => ' fàn', + '笴' => ' gǎn', + '笳' => ' jiā', + '笲' => ' fán', + '笱' => ' gǒu', + '笰' => ' fú', + '筺' => ' kuang', + '筼' => ' yún', + '笔' => ' bǐ', + '箽' => ' dǒng', + '篇' => ' piān', + '篆' => ' zhuàn', + '篅' => ' chuán', + '範' => ' fàn', + '篃' => ' mèi', + '篂' => ' xīng', + '篁' => ' huáng', + '節' => ' jié', + '箿' => ' jí', + '箾' => ' shuò', + '箼' => ' wū', + '築' => ' zhú', + '箻' => ' lǜ', + '箺' => ' chūn', + '箹' => ' yuē', + '箸' => ' zhù', + '箷' => ' yí', + '箶' => ' hú', + '箵' => ' xīng', + '箴' => ' zhēn', + '箳' => ' píng', + '箲' => ' xiǎn', + '篈' => ' fēng', + '篊' => ' huáng', + '箰' => ' sǔn', + '篗' => ' yuè', + '篡' => ' cuàn', + '篠' => ' xiǎo', + '篟' => ' qiàn', + '篞' => ' niè', + '篝' => ' gōu', + '篜' => ' zhēng', + '篛' => ' ruò', + '篚' => ' fěi', + '篙' => ' gāo', + '篘' => ' chōu', + '篖' => ' táng', + '篋' => ' qiè', + '篕' => ' hé', + '篔' => ' yún', + '篓' => ' lǒu', + '篒' => ' shi', + '篑' => ' kuì', + '篐' => ' gu', + '篏' => ' qiàn', + '篎' => ' miǎo', + '篍' => ' qiū', + '篌' => ' hóu', + '箱' => ' xiāng', + '箯' => ' biān', + '筽' => ' o', + '箉' => ' guǎi', + '箓' => ' lù', + '箒' => ' zhǒu', + '箑' => ' shà', + '箐' => ' qìng', + '箏' => ' zhēng', + '箎' => ' chí', + '箍' => ' gū', + '箌' => ' dào', + '箋' => ' jiān', + '箊' => ' yū', + '箈' => ' tái', + '箕' => ' jī', + '箇' => ' gè', + '箆' => ' bì', + '箅' => ' bì', + '箄' => ' bǐ', + '箃' => ' zōu', + '箂' => ' lái', + '箁' => ' póu', + '简' => ' jiǎn', + '筿' => ' xiǎo', + '签' => ' qiān', + '箔' => ' bó', + '箖' => ' lín', + '箮' => ' xuān', + '箣' => ' cè', + '箭' => ' jiàn', + '箬' => ' ruò', + '箫' => ' xiāo', + '箪' => ' dān', + '箩' => ' luó', + '箨' => ' tuò', + '箧' => ' qiè', + '箦' => ' zé', + '箥' => ' bǒ', + '箤' => ' zú', + '箢' => ' yuān', + '算' => ' suàn', + '管' => ' guǎn', + '箠' => ' chuí', + '箟' => ' jùn', + '箞' => ' qiān', + '箝' => ' qián', + '箜' => ' kōng', + '箛' => ' gū', + '箚' => ' zhá', + '箙' => ' fú', + '箘' => ' jùn', + '笕' => ' jiǎn', + '笓' => ' bì', + '穄' => ' jì', + '窄' => ' zhǎi', + '窎' => ' diào', + '窍' => ' qiào', + '窌' => ' jiào', + '窋' => ' zhú', + '窊' => ' wā', + '窉' => ' bǐng', + '窈' => ' yǎo', + '窇' => ' báo', + '窆' => ' biǎn', + '窅' => ' yǎo', + '窃' => ' qiè', + '窐' => ' guī', + '窂' => ' láo', + '突' => ' tū', + '窀' => ' zhūn', + '穿' => ' chuān', + '穾' => ' yào', + '穽' => ' jǐng', + '穼' => ' shēn', + '穻' => ' yū', + '空' => ' kōng', + '穹' => ' qióng', + '窏' => ' wū', + '窑' => ' yáo', + '穷' => ' qióng', + '窞' => ' dàn', + '窨' => ' xūn', + '窧' => ' zhuo', + '窦' => ' dòu', + '窥' => ' kuī', + '窤' => ' guān', + '窣' => ' sū', + '窢' => ' xū', + '窡' => ' zhuó', + '窠' => ' kē', + '窟' => ' kū', + '窝' => ' wō', + '窒' => ' zhì', + '窜' => ' cuàn', + '窛' => ' kòu', + '窚' => ' chéng', + '窙' => ' xiāo', + '窘' => ' jiǒng', + '窗' => ' chuāng', + '窖' => ' jiào', + '窕' => ' tiǎo', + '窔' => ' yào', + '窓' => ' chuāng', + '穸' => ' xī', + '究' => ' jiū', + '窪' => ' wā', + '穐' => ' qiū', + '穚' => ' jiāo', + '穙' => ' pú', + '穘' => ' xiāo', + '穗' => ' suì', + '穖' => ' jǐ', + '穕' => ' qiè', + '穔' => ' huáng', + '穓' => ' yì', + '穒' => ' hè', + '穑' => ' sè', + '穏' => ' wěn', + '穜' => ' zhǒng', + '穎' => ' yǐng', + '積' => ' jī', + '穌' => ' sū', + '穋' => ' lù', + '穊' => ' jì', + '穉' => ' zhì', + '穈' => ' méi', + '穇' => ' cǎn', + '穆' => ' mù', + '穅' => ' kāng', + '穛' => ' zhuō', + '穝' => ' zui', + '穵' => ' wā', + '穪' => ' chēng', + '穴' => ' xué', + '穳' => ' cuán', + '穲' => ' lí', + '穱' => ' zhuō', + '穰' => ' ráng', + '穯' => ' se', + '穮' => ' biāo', + '穭' => ' lǚ', + '穬' => ' kuàng', + '穫' => ' huò', + '穩' => ' wěn', + '穞' => ' lǚ', + '穨' => ' tuí', + '穧' => ' jì', + '穦' => ' pīn', + '穥' => ' yù', + '穤' => ' nuò', + '穣' => ' ráng', + '穢' => ' huì', + '穡' => ' sè', + '穠' => ' nóng', + '穟' => ' suì', + '窩' => ' wō', + '窫' => ' yà', + '笒' => ' cén', + '竭' => ' jié', + '竷' => ' kǎn', + '競' => ' jìng', + '竵' => ' wāi', + '竴' => ' cūn', + '竳' => ' dēng', + '竲' => ' céng', + '竱' => ' zhuǎn', + '竰' => ' sháo', + '端' => ' duān', + '竮' => ' pīng', + '竬' => ' qǔ', + '竹' => ' zhú', + '竫' => ' jìng', + '竪' => ' shù', + '竩' => ' yì', + '竨' => ' diào', + '竧' => ' jìng', + '竦' => ' sǒng', + '童' => ' tóng', + '竤' => ' hóng', + '竣' => ' jùn', + '竢' => ' sì', + '竸' => ' jìng', + '竺' => ' zhú', + '章' => ' zhāng', + '笇' => ' suàn', + '笑' => ' xiào', + '笐' => ' háng', + '笏' => ' hù', + '笎' => ' yuán', + '笍' => ' zhuì', + '笌' => ' yá', + '笋' => ' sǔn', + '笊' => ' zhào', + '笉' => ' qǐn', + '笈' => ' jí', + '笆' => ' bā', + '竻' => ' lè', + '笅' => ' xiáo', + '笄' => ' jī', + '笃' => ' dǔ', + '笂' => ' wan', + '笁' => ' zhú', + '笀' => ' máng', + '竿' => ' gān', + '竾' => ' chí', + '竽' => ' yú', + '竼' => ' péng', + '竡' => ' bai', + '竟' => ' jìng', + '窬' => ' yú', + '窸' => ' xī', + '竂' => ' piáo', + '竁' => ' cuì', + '竀' => ' chēng', + '窿' => ' lóng', + '窾' => ' kuǎn', + '窽' => ' kuan', + '窼' => ' zhāo', + '窻' => ' chuāng', + '窺' => ' kuī', + '窹' => ' wù', + '窷' => ' liào', + '竄' => ' cuàn', + '窶' => ' jù', + '窵' => ' diào', + '窴' => ' tián', + '窳' => ' yǔ', + '窲' => ' cháo', + '窱' => ' tiǎo', + '窰' => ' yáo', + '窯' => ' yáo', + '窮' => ' qióng', + '窭' => ' jù', + '竃' => ' zào', + '竅' => ' qiào', + '竞' => ' jìng', + '竓' => ' hao', + '竝' => ' bìng', + '竜' => ' lóng', + '竛' => ' líng', + '竚' => ' zhù', + '站' => ' zhàn', + '竘' => ' qǔ', + '竗' => ' miào', + '竖' => ' shù', + '竕' => ' fen', + '竔' => ' sheng', + '竒' => ' qí', + '竆' => ' qióng', + '竑' => ' hóng', + '竐' => ' chù', + '竏' => ' qian', + '竎' => ' fù', + '竍' => ' shi', + '竌' => ' chù', + '立' => ' lì', + '竊' => ' qiè', + '竉' => ' lǒng', + '竈' => ' zào', + '竇' => ' dòu', + '缡' => ' lí', + '蕝' => ' jué', + '缣' => ' jiān', + '荵' => ' rěn', + '荿' => ' chéng', + '荾' => ' suī', + '荽' => ' suī', + '荼' => ' tú', + '荻' => ' dí', + '荺' => ' yǔn', + '荹' => ' bù', + '荸' => ' bí', + '荷' => ' hé', + '荶' => ' yín', + '荴' => ' fū', + '莁' => ' wú', + '荳' => ' dòu', + '荲' => ' lí', + '荱' => ' wěi', + '荰' => ' dù', + '药' => ' yào', + '荮' => ' zhòu', + '荭' => ' hóng', + '荬' => ' mǎi', + '荫' => ' yīn', + '荪' => ' sūn', + '莀' => ' chén', + '莂' => ' bié', + '荨' => ' xún', + '莏' => ' suō', + '莙' => ' jūn', + '莘' => ' shēn', + '莗' => ' chē', + '莖' => ' jīng', + '莕' => ' xìng', + '莔' => ' méng', + '莓' => ' méi', + '莒' => ' jǔ', + '莑' => ' péng', + '莐' => ' chén', + '莎' => ' shā', + '莃' => ' xī', + '莍' => ' qiú', + '莌' => ' tuō', + '莋' => ' zuó', + '莊' => ' zhuāng', + '莉' => ' lì', + '莈' => ' mò', + '莇' => ' zhù', + '莆' => ' pú', + '莅' => ' lì', + '莄' => ' gěng', + '荩' => ' jìn', + '荧' => ' yíng', + '莛' => ' tíng', + '荁' => ' huán', + '荋' => ' ér', + '荊' => ' jīng', + '草' => ' cǎo', + '荈' => ' chuǎn', + '荇' => ' xìng', + '荆' => ' jīng', + '荅' => ' dā', + '荄' => ' gāi', + '荃' => ' quán', + '荂' => ' fū', + '荀' => ' xún', + '荍' => ' qiáo', + '茿' => ' zhú', + '茾' => ' qiān', + '茽' => ' zhòng', + '茼' => ' tóng', + '茻' => ' mǎng', + '茺' => ' chōng', + '茹' => ' rú', + '茸' => ' rōng', + '茷' => ' fá', + '茶' => ' chá', + '荌' => ' àn', + '荎' => ' chí', + '荦' => ' luò', + '荛' => ' ráo', + '荥' => ' xíng', + '荤' => ' hūn', + '荣' => ' róng', + '荢' => ' yu', + '荡' => ' dàng', + '荠' => ' jì', + '荟' => ' huì', + '荞' => ' qiáo', + '荝' => ' zé', + '荜' => ' bì', + '荚' => ' jiá', + '荏' => ' rěn', + '荙' => ' dá', + '荘' => ' zhuāng', + '荗' => ' shù', + '荖' => ' lǎo', + '荕' => ' jīn', + '荔' => ' lì', + '荓' => ' píng', + '荒' => ' huāng', + '荑' => ' tí', + '荐' => ' jiàn', + '莚' => ' yán', + '莜' => ' yóu', + '茴' => ' huí', + '菝' => ' bá', + '菧' => ' dǐ', + '菦' => ' qín', + '菥' => ' xī', + '菤' => ' juǎn', + '菣' => ' qìn', + '菢' => ' bào', + '菡' => ' hàn', + '菠' => ' bō', + '菟' => ' tú', + '菞' => ' lí', + '菜' => ' cài', + '菩' => ' pú', + '菛' => ' mén', + '菚' => ' zhàn', + '菙' => ' chuí', + '菘' => ' sōng', + '菗' => ' chóu', + '菖' => ' chāng', + '菕' => ' lún', + '菔' => ' fú', + '菓' => ' guǒ', + '菒' => ' gǎo', + '菨' => ' jiē', + '菪' => ' dàng', + '菐' => ' pú', + '菷' => ' zhǒu', + '萁' => ' qí', + '萀' => ' hǔ', + '菿' => ' dào', + '菾' => ' tián', + '菽' => ' shū', + '菼' => ' tǎn', + '菻' => ' lǐn', + '菺' => ' jiān', + '菹' => ' jū', + '菸' => ' yān', + '菶' => ' běng', + '菫' => ' jǐn', + '菵' => ' wǎng', + '菴' => ' ān', + '菳' => ' qín', + '菲' => ' fēi', + '菱' => ' líng', + '菰' => ' gū', + '華' => ' huá', + '菮' => ' gēng', + '菭' => ' tái', + '菬' => ' qiáo', + '菑' => ' zāi', + '菏' => ' hé', + '莝' => ' cuò', + '莩' => ' fú', + '莳' => ' shí', + '莲' => ' lián', + '莱' => ' lái', + '莰' => ' kǎn', + '莯' => ' mù', + '莮' => ' nán', + '莭' => ' jié', + '莬' => ' wèn', + '莫' => ' mò', + '莪' => ' é', + '莨' => ' làng', + '莵' => ' tu', + '莧' => ' xiàn', + '莦' => ' shāo', + '莥' => ' niǔ', + '莤' => ' sù', + '莣' => ' wáng', + '莢' => ' jiá', + '莡' => ' cuò', + '莠' => ' yǒu', + '莟' => ' hàn', + '莞' => ' guǎn', + '莴' => ' wō', + '莶' => ' xiān', + '菎' => ' kūn', + '菃' => ' qú', + '菍' => ' niè', + '菌' => ' jūn', + '菋' => ' wèi', + '菊' => ' jú', + '菉' => ' lù', + '菈' => ' lā', + '菇' => ' gū', + '菆' => ' zōu', + '菅' => ' jiān', + '菄' => ' dōng', + '菂' => ' dì', + '获' => ' huò', + '菁' => ' jīng', + '菀' => ' wǎn', + '莿' => ' cì', + '莾' => ' mǎng', + '莽' => ' mǎng', + '莼' => ' chún', + '莻' => ' gòng', + '莺' => ' yīng', + '莹' => ' yíng', + '莸' => ' yóu', + '茵' => ' yīn', + '茳' => ' jiāng', + '萃' => ' cuì', + '芥' => ' jiè', + '芯' => ' xīn', + '芮' => ' ruì', + '芭' => ' bā', + '芬' => ' fēn', + '芫' => ' yán', + '芪' => ' qí', + '芩' => ' qín', + '芨' => ' jī', + '芧' => ' xù', + '芦' => ' lú', + '芤' => ' kōu', + '花' => ' huā', + '芣' => ' fú', + '芢' => ' rén', + '芡' => ' qiàn', + '芠' => ' wén', + '芟' => ' shān', + '芞' => ' qì', + '芝' => ' zhī', + '芜' => ' wú', + '芛' => ' wěi', + '芚' => ' tún', + '芰' => ' jì', + '芲' => ' huā', + '芘' => ' pí', + '芿' => ' rèng', + '苉' => ' pǐ', + '苈' => ' lì', + '苇' => ' wěi', + '苆' => ' qie', + '苅' => ' yì', + '苄' => ' biàn', + '苃' => ' yǒu', + '苂' => ' yín', + '苁' => ' cōng', + '苀' => ' háng', + '芾' => ' fèi', + '芳' => ' fāng', + '芽' => ' yá', + '芼' => ' mào', + '芻' => ' chú', + '芺' => ' ǎo', + '芹' => ' qín', + '芸' => ' yún', + '芷' => ' zhǐ', + '芶' => ' gǒu', + '芵' => ' jué', + '芴' => ' wù', + '芙' => ' fú', + '芗' => ' xiāng', + '苋' => ' xiàn', + '艱' => ' jiān', + '艻' => ' lè', + '艺' => ' yì', + '艹' => ' cao', + '艸' => ' cǎo', + '艷' => ' yàn', + '艶' => ' yàn', + '艵' => ' pīng', + '艴' => ' fú', + '艳' => ' yàn', + '色' => ' sè', + '艰' => ' jiān', + '艽' => ' jiāo', + '良' => ' liáng', + '艮' => ' gěn', + '艭' => ' shuāng', + '艬' => ' chán', + '艫' => ' lú', + '艪' => ' lǔ', + '艩' => ' qí', + '艨' => ' méng', + '艧' => ' huò', + '艦' => ' jiàn', + '艼' => ' tīng', + '艾' => ' ài', + '芖' => ' zhì', + '芋' => ' yù', + '芕' => ' suī', + '芔' => ' huì', + '芓' => ' zì', + '芒' => ' máng', + '芑' => ' qǐ', + '芐' => ' hù', + '芏' => ' dù', + '芎' => ' qiōng', + '芍' => ' sháo', + '芌' => ' yù', + '芊' => ' qiān', + '艿' => ' nǎi', + '芉' => ' gān', + '芈' => ' mǐ', + '芇' => ' mián', + '芆' => ' chāi', + '芅' => ' yì', + '芄' => ' wán', + '芃' => ' péng', + '节' => ' jié', + '芁' => ' jiāo', + '芀' => ' tiáo', + '苊' => ' è', + '苌' => ' cháng', + '茲' => ' zī', + '茍' => ' jì', + '茗' => ' míng', + '茖' => ' gé', + '茕' => ' qióng', + '茔' => ' yíng', + '茓' => ' xué', + '茒' => ' yuán', + '茑' => ' niǎo', + '茐' => ' cong', + '茏' => ' lóng', + '茎' => ' jīng', + '茌' => ' chí', + '茙' => ' róng', + '茋' => ' dǐ', + '茊' => ' zī', + '茉' => ' mò', + '茈' => ' cí', + '茇' => ' bá', + '茆' => ' máo', + '茅' => ' máo', + '茄' => ' jiā', + '范' => ' fàn', + '茂' => ' mào', + '茘' => ' lì', + '茚' => ' yìn', + '茀' => ' fú', + '茧' => ' jiǎn', + '茱' => ' zhū', + '茰' => ' yú', + '茯' => ' fú', + '茮' => ' jiāo', + '茭' => ' jiāo', + '茬' => ' chá', + '茫' => ' máng', + '茪' => ' guāng', + '茩' => ' gòu', + '茨' => ' cí', + '茦' => ' cì', + '茛' => ' gèn', + '茥' => ' guī', + '茤' => ' jì', + '茣' => ' wú', + '茢' => ' liè', + '茡' => ' zì', + '茠' => ' hāo', + '茟' => ' yù', + '茞' => ' chén', + '茝' => ' chǎi', + '茜' => ' qiàn', + '茁' => ' zhuó', + '苿' => ' wèi', + '苍' => ' cāng', + '苙' => ' lì', + '苣' => ' jù', + '苢' => ' yǐ', + '苡' => ' yǐ', + '苠' => ' mín', + '苟' => ' gǒu', + '苞' => ' bāo', + '苝' => ' bèi', + '苜' => ' mù', + '苛' => ' kē', + '苚' => ' yòng', + '苘' => ' qǐng', + '若' => ' ruò', + '苗' => ' miáo', + '苖' => ' dí', + '苕' => ' sháo', + '苔' => ' tái', + '苓' => ' líng', + '苒' => ' rǎn', + '苑' => ' yuàn', + '苐' => ' tí', + '苏' => ' sū', + '苎' => ' zhù', + '苤' => ' piě', + '苦' => ' kǔ', + '苾' => ' bì', + '苳' => ' dōng', + '苽' => ' gū', + '苼' => ' shēng', + '苻' => ' fú', + '苺' => ' méi', + '苹' => ' píng', + '苸' => ' hū', + '苷' => ' gān', + '苶' => ' nié', + '苵' => ' dié', + '苴' => ' jū', + '苲' => ' zhǎ', + '苧' => ' níng', + '英' => ' yīng', + '苰' => ' hóng', + '苯' => ' běn', + '苮' => ' xiān', + '苭' => ' yǎo', + '苬' => ' xiú', + '苫' => ' shān', + '苪' => ' bǐng', + '苩' => ' bó', + '苨' => ' nǐ', + '萂' => ' hé', + '萄' => ' táo', + '艤' => ' yǐ', + '蔕' => ' dì', + '蔟' => ' cù', + '蔞' => ' lóu', + '蔝' => ' mǐ', + '蔜' => ' áo', + '蔛' => ' hú', + '蔚' => ' wèi', + '蔙' => ' xuàn', + '蔘' => ' shēn', + '蔗' => ' zhè', + '蔖' => ' cuó', + '蔔' => ' bó', + '蔡' => ' cài', + '蔓' => ' màn', + '蔒' => ' xūn', + '蔑' => ' miè', + '蔐' => ' dí', + '蔏' => ' shāng', + '蔎' => ' shè', + '蔍' => ' lù', + '蔌' => ' sù', + '蔋' => ' dí', + '蔊' => ' hǎn', + '蔠' => ' zhōng', + '蔢' => ' pó', + '蔈' => ' biāo', + '蔯' => ' chén', + '蔹' => ' liǎn', + '蔸' => ' dōu', + '蔷' => ' qiáng', + '蔶' => ' ze', + '蔵' => ' zāng', + '蔴' => ' má', + '蔳' => ' qiàn', + '蔲' => ' kòu', + '蔱' => ' shā', + '蔰' => ' hù', + '蔮' => ' guó', + '蔣' => ' jiǎng', + '蔭' => ' yīn', + '蔬' => ' shū', + '蔫' => ' niān', + '蔪' => ' jiàn', + '蔩' => ' yín', + '蔨' => ' juàn', + '蔧' => ' huì', + '蔦' => ' niǎo', + '蔥' => ' cōng', + '蔤' => ' mì', + '蔉' => ' gǔn', + '蔇' => ' jì', + '蔻' => ' kòu', + '蓡' => ' shēn', + '蓫' => ' chù', + '蓪' => ' tōng', + '蓩' => ' mǎo', + '蓨' => ' tiáo', + '蓧' => ' diào', + '蓦' => ' mò', + '蓥' => ' yíng', + '蓤' => ' ling', + '蓣' => ' yù', + '蓢' => ' lǎng', + '蓠' => ' lí', + '蓭' => ' ān', + '蓟' => ' jì', + '蓞' => ' dàn', + '蓝' => ' lán', + '蓜' => ' pei', + '蓛' => ' cè', + '蓚' => ' tiáo', + '蓙' => ' zuo', + '蓘' => ' gǔn', + '蓗' => ' zǒng', + '蓖' => ' bì', + '蓬' => ' péng', + '蓮' => ' lián', + '蔆' => ' líng', + '蓻' => ' zí', + '蔅' => ' yán', + '蔄' => ' màn', + '蔃' => ' qiáng', + '蔂' => ' léi', + '蔁' => ' zhāng', + '蔀' => ' bù', + '蓿' => ' xu', + '蓾' => ' lǔ', + '蓽' => ' bì', + '蓼' => ' liǎo', + '蓺' => ' yì', + '蓯' => ' cōng', + '蓹' => ' yù', + '蓸' => ' cáo', + '蓷' => ' tuī', + '蓶' => ' wéi', + '蓵' => ' jié', + '蓴' => ' chún', + '蓳' => ' jǐn', + '蓲' => ' qiū', + '蓱' => ' píng', + '蓰' => ' xǐ', + '蔺' => ' lìn', + '蔼' => ' ǎi', + '蓔' => ' yǎo', + '蕽' => ' nóng', + '薇' => ' wēi', + '薆' => ' ài', + '薅' => ' hāo', + '薄' => ' báo', + '薃' => ' hào', + '薂' => ' xí', + '薁' => ' yù', + '薀' => ' yùn', + '蕿' => ' xuān', + '蕾' => ' lěi', + '蕼' => ' sì', + '薉' => ' huì', + '蕻' => ' hóng', + '蕺' => ' jí', + '蕹' => ' wèng', + '蕸' => ' xiá', + '蕷' => ' yù', + '蕶' => ' líng', + '蕵' => ' sūn', + '蕴' => ' yùn', + '蕳' => ' jiān', + '蕲' => ' qí', + '薈' => ' huì', + '薊' => ' jì', + '蕰' => ' wēn', + '薗' => ' yuán', + '薡' => ' dǐng', + '薠' => ' fán', + '薟' => ' xiān', + '薞' => ' sūn', + '薝' => ' zhān', + '薜' => ' bì', + '薛' => ' xuē', + '薚' => ' tāng', + '薙' => ' tì', + '薘' => ' dá', + '薖' => ' kē', + '薋' => ' cí', + '薕' => ' lián', + '薔' => ' qiáng', + '薓' => ' shēn', + '薒' => ' càn', + '薑' => ' jiāng', + '薐' => ' léng', + '薏' => ' yì', + '薎' => ' miè', + '薍' => ' wàn', + '薌' => ' xiāng', + '蕱' => ' shao', + '蕯' => ' lóng', + '蔽' => ' bì', + '蕉' => ' jiāo', + '蕓' => ' yún', + '蕒' => ' mǎi', + '蕑' => ' jiān', + '蕐' => ' huá', + '蕏' => ' chú', + '蕎' => ' qiáo', + '蕍' => ' yú', + '蕌' => ' lěi', + '蕋' => ' ruǐ', + '蕊' => ' ruǐ', + '蕈' => ' xùn', + '蕕' => ' yóu', + '蕇' => ' diǎn', + '蕆' => ' chǎn', + '蕅' => ' ǒu', + '蕄' => ' méng', + '蕃' => ' fān', + '蕂' => ' shèng', + '蕁' => ' qián', + '蕀' => ' jí', + '蔿' => ' wěi', + '蔾' => ' lí', + '蕔' => ' bāo', + '蕖' => ' qú', + '蕮' => ' xì', + '蕣' => ' shùn', + '蕭' => ' xiāo', + '蕬' => ' sī', + '蕫' => ' dǒng', + '蕪' => ' wú', + '蕩' => ' dàng', + '蕨' => ' jué', + '蕧' => ' fù', + '蕦' => ' xū', + '蕥' => ' yǎ', + '蕤' => ' ruí', + '蕢' => ' kuì', + '蕗' => ' lù', + '蕡' => ' fén', + '蕠' => ' rú', + '蕟' => ' fà', + '蕞' => ' zuì', + '碣' => ' jié', + '蕜' => ' fěi', + '蕛' => ' tí', + '蕚' => ' è', + '蕙' => ' huì', + '蕘' => ' ráo', + '蓕' => ' guì', + '蓓' => ' bèi', + '萅' => ' chūn', + '葅' => ' zū', + '葏' => ' jīng', + '葎' => ' lǜ', + '葍' => ' fú', + '葌' => ' jiān', + '葋' => ' qú', + '葊' => ' ān', + '葉' => ' yè', + '葈' => ' xǐ', + '葇' => ' róu', + '葆' => ' bǎo', + '葄' => ' zuò', + '葑' => ' fēng', + '葃' => ' zuò', + '葂' => ' miǎn', + '葁' => ' jiāng', + '葀' => ' kuò', + '萿' => ' kuò', + '萾' => ' yíng', + '落' => ' luò', + '萼' => ' è', + '萻' => ' ān', + '萺' => ' mào', + '葐' => ' pén', + '葒' => ' hóng', + '萸' => ' yú', + '葟' => ' huáng', + '葩' => ' pā', + '葨' => ' wēi', + '葧' => ' bó', + '葦' => ' wěi', + '葥' => ' jiàn', + '葤' => ' zhòu', + '董' => ' dǒng', + '葢' => ' gài', + '葡' => ' pú', + '葠' => ' shēn', + '葞' => ' mǐ', + '葓' => ' hóng', + '葝' => ' qíng', + '葜' => ' qiā', + '葛' => ' gé', + '葚' => ' rèn', + '葙' => ' xiāng', + '葘' => ' zī', + '著' => ' zhe', + '葖' => ' tū', + '葕' => ' yàn', + '葔' => ' hóu', + '萹' => ' biǎn', + '萷' => ' xiāo', + '葫' => ' hú', + '萑' => ' huán', + '萛' => ' jiū', + '萚' => ' tuò', + '萙' => ' zhen', + '萘' => ' nài', + '萗' => ' cè', + '萖' => ' wǎn', + '萕' => ' qí', + '萔' => ' tiáo', + '萓' => ' yí', + '萒' => ' yǎn', + '萐' => ' shà', + '萝' => ' luó', + '萏' => ' dàn', + '萎' => ' wēi', + '萍' => ' píng', + '萌' => ' méng', + '萋' => ' qī', + '萊' => ' lái', + '萉' => ' fèi', + '萈' => ' huán', + '萇' => ' cháng', + '萆' => ' bì', + '萜' => ' tiē', + '萞' => ' bi', + '萶' => ' chǔn', + '萫' => ' xiàng', + '萵' => ' wō', + '萴' => ' cè', + '萳' => ' nǎn', + '萲' => ' xuān', + '萱' => ' xuān', + '萰' => ' liàn', + '萯' => ' fù', + '萮' => ' yú', + '萭' => ' yǔ', + '萬' => ' wàn', + '萪' => ' kē', + '萟' => ' yi', + '萩' => ' qiū', + '萨' => ' sà', + '萧' => ' xiāo', + '萦' => ' yíng', + '营' => ' yíng', + '萤' => ' yíng', + '萣' => ' dìng', + '萢' => ' pao', + '萡' => ' bo', + '萠' => ' méng', + '葪' => ' jì', + '葬' => ' zàng', + '蓒' => ' xuān', + '蒭' => ' chú', + '蒷' => ' yún', + '蒶' => ' fén', + '蒵' => ' xí', + '蒴' => ' shuò', + '蒳' => ' nà', + '蒲' => ' pú', + '蒱' => ' pú', + '蒰' => ' pán', + '蒯' => ' kuǎi', + '蒮' => ' yù', + '蒬' => ' yuān', + '蒹' => ' jiān', + '蒫' => ' cuó', + '蒪' => ' pò', + '蒩' => ' zū', + '蒨' => ' qiàn', + '蒧' => ' diǎn', + '蒦' => ' huò', + '蒥' => ' liú', + '蒤' => ' tú', + '蒣' => ' xú', + '蒢' => ' chú', + '蒸' => ' zhēng', + '蒺' => ' jí', + '蒠' => ' xī', + '蓇' => ' gǔ', + '蓑' => ' suō', + '蓐' => ' rù', + '蓏' => ' luǒ', + '蓎' => ' táng', + '蓍' => ' shī', + '蓌' => ' cuò', + '蓋' => ' gài', + '蓊' => ' wěng', + '蓉' => ' róng', + '蓈' => ' láng', + '蓆' => ' xí', + '蒻' => ' ruò', + '蓅' => ' liú', + '蓄' => ' xù', + '蓃' => ' sōu', + '蓂' => ' míng', + '蓁' => ' zhēn', + '蓀' => ' sūn', + '蒿' => ' hāo', + '蒾' => ' mí', + '蒽' => ' ēn', + '蒼' => ' cāng', + '蒡' => ' bàng', + '蒟' => ' jǔ', + '葭' => ' jiā', + '葹' => ' shī', + '蒃' => ' zhuàn', + '蒂' => ' dì', + '蒁' => ' shù', + '蒀' => ' yūn', + '葿' => ' méi', + '葾' => ' yuān', + '葽' => ' yāo', + '葼' => ' zōng', + '葻' => ' lán', + '葺' => ' qì', + '葸' => ' xǐ', + '蒅' => ' ran', + '葷' => ' hūn', + '葶' => ' tíng', + '葵' => ' kuí', + '葴' => ' zhēn', + '葳' => ' wēi', + '葲' => ' quán', + '葱' => ' cōng', + '葰' => ' suī', + '葯' => ' yào', + '葮' => ' duàn', + '蒄' => ' guān', + '蒆' => ' xuē', + '蒞' => ' lì', + '蒓' => ' chún', + '蒝' => ' yuán', + '蒜' => ' suàn', + '蒛' => ' quē', + '蒚' => ' lì', + '蒙' => ' méng', + '蒘' => ' rú', + '蒗' => ' làng', + '蒖' => ' zhēn', + '蒕' => ' yūn', + '蒔' => ' shí', + '蒒' => ' shī', + '蒇' => ' chǎn', + '蒑' => ' yìn', + '蒐' => ' sōu', + '蒏' => ' you', + '蒎' => ' pài', + '蒍' => ' wěi', + '蒌' => ' lóu', + '蒋' => ' jiǎng', + '蒊' => ' huā', + '蒉' => ' kuì', + '蒈' => ' kǎi', + '艥' => ' jí', + '艣' => ' lǔ', + '缤' => ' bīn', + '耴' => ' yì', + '耾' => ' hóng', + '耽' => ' dān', + '耼' => ' dān', + '耻' => ' chǐ', + '耺' => ' yún', + '耹' => ' qín', + '耸' => ' sǒng', + '耷' => ' dā', + '耶' => ' yé', + '耵' => ' dīng', + '耳' => ' ěr', + '聀' => ' zhí', + '耲' => ' huái', + '耱' => ' mò', + '耰' => ' yōu', + '耯' => ' huò', + '耮' => ' lào', + '耭' => ' jī', + '耬' => ' lóu', + '耫' => ' zhá', + '耪' => ' pǎng', + '耩' => ' jiǎng', + '耿' => ' gěng', + '聁' => ' pàn', + '耧' => ' lóu', + '聎' => ' tiāo', + '聘' => ' pìn', + '聗' => ' liè', + '聖' => ' shèng', + '聕' => ' hào', + '联' => ' lián', + '聓' => ' xu', + '聒' => ' guā', + '聑' => ' tiē', + '聐' => ' yà', + '聏' => ' ér', + '聍' => ' níng', + '聂' => ' niè', + '职' => ' zhí', + '聋' => ' lóng', + '聊' => ' liáo', + '聉' => ' wà', + '聈' => ' yǒu', + '聇' => ' zhēng', + '聆' => ' líng', + '聅' => ' chè', + '聄' => ' zhěn', + '聃' => ' dān', + '耨' => ' nòu', + '耦' => ' ǒu', + '聚' => ' jù', + '耀' => ' yào', + '耊' => ' diè', + '耉' => ' gǒu', + '耈' => ' gǒu', + '耇' => ' gǒu', + '耆' => ' qí', + '者' => ' zhě', + '耄' => ' mào', + '考' => ' kǎo', + '耂' => ' lǎo', + '老' => ' lǎo', + '翿' => ' dào', + '而' => ' ér', + '翾' => ' xuān', + '翽' => ' huì', + '翼' => ' yì', + '翻' => ' fān', + '翺' => ' áo', + '翹' => ' qiào', + '翸' => ' pěn', + '翷' => ' lín', + '翶' => ' ao', + '翵' => ' hóu', + '耋' => ' dié', + '耍' => ' shuǎ', + '耥' => ' tāng', + '耚' => ' pī', + '耤' => ' jí', + '耣' => ' lǔn', + '耢' => ' lào', + '耡' => ' chú', + '耠' => ' huō', + '耟' => ' jù', + '耞' => ' jiā', + '耝' => ' qù', + '耜' => ' sì', + '耛' => ' yí', + '耙' => ' bà', + '耎' => ' ruǎn', + '耘' => ' yún', + '耗' => ' hào', + '耖' => ' chào', + '耕' => ' gēng', + '耔' => ' zǐ', + '耓' => ' tīng', + '耒' => ' lěi', + '耑' => ' duān', + '耐' => ' nài', + '耏' => ' nài', + '聙' => ' jīng', + '聛' => ' bǐ', + '翳' => ' yì', + '肜' => ' róng', + '肦' => ' fén', + '肥' => ' féi', + '肤' => ' fū', + '肣' => ' hán', + '肢' => ' zhī', + '股' => ' gǔ', + '肠' => ' cháng', + '肟' => ' wò', + '肞' => ' chā', + '肝' => ' gān', + '肛' => ' gāng', + '肨' => ' pàng', + '肚' => ' dù', + '肙' => ' yuàn', + '肘' => ' zhǒu', + '肗' => ' rǔ', + '肖' => ' xiào', + '肕' => ' rèn', + '肔' => ' yǐ', + '肓' => ' huāng', + '肒' => ' huàn', + '肑' => ' bó', + '肧' => ' pēi', + '肩' => ' jiān', + '肏' => ' cào', + '肶' => ' pí', + '胀' => ' zhàng', + '肿' => ' zhǒng', + '肾' => ' shèn', + '肽' => ' tài', + '肼' => ' jǐng', + '肻' => ' kěn', + '肺' => ' fèi', + '肹' => ' xī', + '肸' => ' xī', + '肷' => ' qiǎn', + '肵' => ' qí', + '肪' => ' fáng', + '肴' => ' yáo', + '肳' => ' wěn', + '育' => ' yù', + '肱' => ' gōng', + '肰' => ' rán', + '肯' => ' kěn', + '肮' => ' āng', + '肭' => ' nà', + '肬' => ' yóu', + '肫' => ' zhūn', + '肐' => ' gē', + '肎' => ' kěn', + '聜' => ' dǐ', + '聨' => ' lian', + '聲' => ' shēng', + '聱' => ' áo', + '聰' => ' cōng', + '聯' => ' lián', + '聮' => ' lián', + '聭' => ' kuì', + '聬' => ' wěng', + '聫' => ' lián', + '聪' => ' cōng', + '聩' => ' kuì', + '聧' => ' kuī', + '聴' => ' tīng', + '聦' => ' cōng', + '聥' => ' jǔ', + '聤' => ' tíng', + '聣' => ' ní', + '聢' => ' ding', + '聡' => ' cōng', + '聠' => ' pīng', + '聟' => ' xù', + '聞' => ' wén', + '聝' => ' guó', + '聳' => ' sǒng', + '聵' => ' kuì', + '肍' => ' qiú', + '肂' => ' sì', + '肌' => ' jī', + '肋' => ' lē', + '肊' => ' yì', + '肉' => ' ròu', + '肈' => ' zhào', + '肇' => ' zhào', + '肆' => ' sì', + '肅' => ' sù', + '肄' => ' yì', + '肃' => ' sù', + '肁' => ' zhào', + '聶' => ' niè', + '肀' => ' yù', + '聿' => ' yù', + '聾' => ' lóng', + '聽' => ' tīng', + '聼' => ' tīng', + '聻' => ' nǐ', + '聺' => ' qié', + '聹' => ' níng', + '聸' => ' dān', + '職' => ' zhí', + '翴' => ' lián', + '翲' => ' piāo', + '胂' => ' shèn', + '罤' => ' tí', + '置' => ' zhì', + '罭' => ' yù', + '罬' => ' zhuó', + '罫' => ' guà', + '罪' => ' zuì', + '罩' => ' zhào', + '罨' => ' yǎn', + '罧' => ' shèn', + '罦' => ' fú', + '罥' => ' juàn', + '罣' => ' guà', + '罰' => ' fá', + '罢' => ' bà', + '罡' => ' gāng', + '罠' => ' mín', + '罟' => ' gǔ', + '罞' => ' máo', + '罝' => ' jū', + '罜' => ' zhǔ', + '罛' => ' gū', + '罚' => ' fá', + '罙' => ' mí', + '罯' => ' ǎn', + '罱' => ' lǎn', + '罗' => ' luó', + '罾' => ' zēng', + '羈' => ' jī', + '羇' => ' jī', + '羆' => ' pí', + '羅' => ' luó', + '羄' => ' zhào', + '羃' => ' mì', + '羂' => ' juàn', + '羁' => ' jī', + '羀' => ' liǔ', + '罿' => ' chōng', + '罽' => ' jì', + '署' => ' shǔ', + '罼' => ' bì', + '罻' => ' wèi', + '罺' => ' cháo', + '罹' => ' lí', + '罸' => ' fá', + '罷' => ' bà', + '罶' => ' liǔ', + '罵' => ' mà', + '罴' => ' pí', + '罳' => ' sī', + '罘' => ' fú', + '罖' => ' luó', + '羊' => ' yáng', + '缰' => ' jiāng', + '缺' => ' quē', + '缹' => ' fǒu', + '缸' => ' gāng', + '缷' => ' xiè', + '缶' => ' fǒu', + '缵' => ' zuǎn', + '缴' => ' jiǎo', + '缳' => ' huán', + '缲' => ' qiāo', + '缱' => ' qiǎn', + '缯' => ' zēng', + '缼' => ' qi', + '缮' => ' shàn', + '缭' => ' liáo', + '缬' => ' xié', + '缫' => ' sāo', + '缪' => ' móu', + '缩' => ' suō', + '缨' => ' yīng', + '缧' => ' léi', + '缦' => ' màn', + '缥' => ' piāo', + '缻' => ' fǒu', + '缽' => ' bō', + '罕' => ' hǎn', + '罊' => ' qì', + '罔' => ' wǎng', + '罓' => ' gāng', + '罒' => ' wǎng', + '网' => ' wǎng', + '罐' => ' guàn', + '罏' => ' lú', + '罎' => ' tán', + '罍' => ' léi', + '罌' => ' yīng', + '罋' => ' wèng', + '罉' => ' cang', + '缾' => ' píng', + '罈' => ' tán', + '罇' => ' zūn', + '罆' => ' guàn', + '罅' => ' xià', + '罄' => ' qìng', + '罃' => ' yīng', + '罂' => ' yīng', + '罁' => ' gāng', + '罀' => ' zhao', + '缿' => ' xiàng', + '羉' => ' luán', + '羋' => ' mǐ', + '翱' => ' áo', + '翌' => ' yì', + '翖' => ' xì', + '翕' => ' xī', + '翔' => ' xiáng', + '翓' => ' xié', + '習' => ' xí', + '翑' => ' qú', + '翐' => ' zhì', + '翏' => ' liù', + '翎' => ' líng', + '翍' => ' pī', + '翋' => ' lā', + '翘' => ' qiào', + '翊' => ' yì', + '翉' => ' běn', + '翈' => ' xiá', + '翇' => ' fú', + '翆' => ' cuì', + '翅' => ' chì', + '翄' => ' chì', + '翃' => ' hóng', + '翂' => ' fēn', + '翁' => ' wēng', + '翗' => ' ké', + '翙' => ' huì', + '羿' => ' yì', + '翦' => ' jiǎn', + '翰' => ' hàn', + '翯' => ' hè', + '翮' => ' hé', + '翭' => ' hóu', + '翬' => ' huī', + '翫' => ' wán', + '翪' => ' zōng', + '翩' => ' piān', + '翨' => ' chì', + '翧' => ' xuān', + '翥' => ' zhù', + '翚' => ' huī', + '翤' => ' chì', + '翣' => ' shà', + '翢' => ' dào', + '翡' => ' fěi', + '翠' => ' cuì', + '翟' => ' dí', + '翞' => ' jiāng', + '翝' => ' hóng', + '翜' => ' shà', + '翛' => ' xiāo', + '翀' => ' chōng', + '羾' => ' gòng', + '羌' => ' qiāng', + '羘' => ' zāng', + '羢' => ' róng', + '羡' => ' xiàn', + '羠' => ' yí', + '羟' => ' qiǎng', + '羞' => ' xiū', + '羝' => ' dī', + '羜' => ' zhù', + '羛' => ' yì', + '羚' => ' líng', + '羙' => ' gāo', + '羗' => ' qiāng', + '群' => ' qún', + '羖' => ' gǔ', + '羕' => ' yàng', + '羔' => ' gāo', + '羓' => ' bā', + '羒' => ' fén', + '羑' => ' yǒu', + '羐' => ' yǒu', + '羏' => ' yáng', + '美' => ' měi', + '羍' => ' dá', + '羣' => ' qún', + '羥' => ' qiǎng', + '羽' => ' yǔ', + '羲' => ' xī', + '羼' => ' chàn', + '羻' => ' qiàng', + '羺' => ' nóu', + '羹' => ' gēng', + '羸' => ' léi', + '羷' => ' liǎn', + '羶' => ' shān', + '羵' => ' fén', + '羴' => ' shān', + '羳' => ' fán', + '羱' => ' yuán', + '羦' => ' huán', + '羰' => ' tāng', + '羯' => ' jié', + '羮' => ' gēng', + '羭' => ' yú', + '羬' => ' qián', + '羫' => ' qiāng', + '羪' => ' yang', + '義' => ' yì', + '羨' => ' xiàn', + '羧' => ' suō', + '胁' => ' xié', + '胃' => ' wèi', + '艢' => ' qiáng', + '臕' => ' biāo', + '臟' => ' zàng', + '臞' => ' qú', + '臝' => ' luǒ', + '臜' => ' zā', + '臛' => ' huò', + '臚' => ' lú', + '臙' => ' yān', + '臘' => ' là', + '臗' => ' kuān', + '臖' => ' xìng', + '臔' => ' xiàn', + '臡' => ' ní', + '臓' => ' zàng', + '臒' => ' wò', + '臑' => ' nào', + '臐' => ' xūn', + '臏' => ' bìn', + '臎' => ' cuì', + '臍' => ' qí', + '臌' => ' gǔ', + '臋' => ' tún', + '臊' => ' sāo', + '臠' => ' luán', + '臢' => ' zā', + '臈' => ' là', + '臯' => ' gāo', + '臹' => ' xiū', + '臸' => ' zhī', + '臷' => ' dié', + '臶' => ' jiàn', + '臵' => ' gé', + '致' => ' zhì', + '至' => ' zhì', + '臲' => ' niè', + '臱' => ' mián', + '臰' => ' chòu', + '臮' => ' jì', + '臣' => ' chén', + '臭' => ' chòu', + '臬' => ' niè', + '臫' => ' jiǎo', + '自' => ' zì', + '臩' => ' guǎng', + '臨' => ' lín', + '臧' => ' zāng', + '臦' => ' guàng', + '臥' => ' wò', + '臤' => ' qiān', + '臉' => ' liǎn', + '臇' => ' juǎn', + '臻' => ' zhēn', + '膡' => ' yìng', + '膫' => ' liáo', + '膪' => ' chuài', + '膩' => ' nì', + '膨' => ' péng', + '膧' => ' tóng', + '膦' => ' lìn', + '膥' => ' chūn', + '膤' => ' xue', + '膣' => ' zhì', + '膢' => ' lǘ', + '膠' => ' jiāo', + '膭' => ' guī', + '膟' => ' lǜ', + '膞' => ' zhuān', + '膝' => ' xī', + '膜' => ' mó', + '膛' => ' táng', + '膚' => ' fū', + '膙' => ' jiǎng', + '膘' => ' biāo', + '膗' => ' chuái', + '膖' => ' pāng', + '膬' => ' cuì', + '膮' => ' xiāo', + '臆' => ' yì', + '膻' => ' shān', + '臅' => ' chù', + '臄' => ' jué', + '臃' => ' yōng', + '臂' => ' bì', + '臁' => ' lián', + '臀' => ' tún', + '膿' => ' nóng', + '膾' => ' kuài', + '膽' => ' dǎn', + '膼' => ' zhuā', + '膺' => ' yīng', + '膯' => ' tēng', + '膹' => ' fèn', + '膸' => ' suǐ', + '膷' => ' xiāng', + '膶' => ' rùn', + '膵' => ' cuì', + '膴' => ' hū', + '膳' => ' shàn', + '膲' => ' jiāo', + '膱' => ' zhí', + '膰' => ' fán', + '臺' => ' tái', + '臼' => ' jiù', + '膔' => ' lù', + '舽' => ' páng', + '艇' => ' tǐng', + '艆' => ' láng', + '艅' => ' yú', + '艄' => ' shāo', + '艃' => ' lí', + '艂' => ' féng', + '艁' => ' zào', + '艀' => ' fú', + '舿' => ' kua', + '舾' => ' xī', + '舼' => ' qióng', + '艉' => ' wěi', + '舻' => ' lú', + '舺' => ' xiá', + '船' => ' chuán', + '舸' => ' gě', + '舷' => ' xián', + '舶' => ' bó', + '舵' => ' duò', + '舴' => ' zé', + '舳' => ' zhú', + '舲' => ' líng', + '艈' => ' yù', + '艊' => ' bó', + '舰' => ' jiàn', + '艗' => ' yì', + '艡' => ' dāng', + '艠' => ' deng', + '艟' => ' chōng', + '艞' => ' yào', + '艝' => ' xue', + '艜' => ' dài', + '艛' => ' lóu', + '艚' => ' cáo', + '艙' => ' cāng', + '艘' => ' sōu', + '艖' => ' chā', + '艋' => ' měng', + '艕' => ' bàng', + '艔' => ' dou', + '艓' => ' dié', + '艒' => ' mù', + '艑' => ' biàn', + '艐' => ' kè', + '艏' => ' shǒu', + '艎' => ' huáng', + '艍' => ' jū', + '艌' => ' niàn', + '舱' => ' cāng', + '舯' => ' zhōng', + '臽' => ' xiàn', + '舉' => ' jǔ', + '舓' => ' shì', + '舒' => ' shū', + '舑' => ' tān', + '舐' => ' shì', + '舏' => ' jiǔ', + '舎' => ' she', + '舍' => ' shě', + '舌' => ' shé', + '舋' => ' xìn', + '舊' => ' jiù', + '興' => ' xìng', + '舕' => ' tàn', + '與' => ' yǔ', + '舆' => ' yú', + '舅' => ' jiù', + '舄' => ' xì', + '舃' => ' xì', + '舂' => ' chōng', + '舁' => ' yú', + '舀' => ' yǎo', + '臿' => ' chā', + '臾' => ' yú', + '舔' => ' tiǎn', + '舖' => ' pù', + '舮' => ' lu', + '舣' => ' yǐ', + '舭' => ' bǐ', + '般' => ' bān', + '舫' => ' fǎng', + '航' => ' háng', + '舩' => ' chuán', + '舨' => ' bǎn', + '舧' => ' fán', + '舦' => ' tài', + '舥' => ' pā', + '舤' => ' fan', + '舢' => ' shān', + '舗' => ' pù', + '舡' => ' chuán', + '舠' => ' dāo', + '舟' => ' zhōu', + '舞' => ' wǔ', + '舝' => ' xiá', + '舜' => ' shùn', + '舛' => ' chuǎn', + '舚' => ' tiàn', + '舙' => ' huà', + '舘' => ' guǎn', + '膕' => ' guó', + '膓' => ' cháng', + '胄' => ' zhòu', + '脄' => ' méi', + '脎' => ' sà', + '脍' => ' kuài', + '脌' => ' nin', + '脋' => ' xie', + '脊' => ' jí', + '脉' => ' mài', + '脈' => ' mài', + '脇' => ' xié', + '脆' => ' cuì', + '脅' => ' xié', + '脃' => ' cuì', + '脐' => ' qí', + '脂' => ' zhī', + '脁' => ' tiǎo', + '脀' => ' chéng', + '胿' => ' guī', + '胾' => ' zì', + '能' => ' néng', + '胼' => ' pián', + '胻' => ' héng', + '胺' => ' àn', + '胹' => ' ér', + '脏' => ' zàng', + '脑' => ' nǎo', + '胷' => ' xiōng', + '脞' => ' cuǒ', + '脨' => ' cù', + '脧' => ' juān', + '脦' => ' de', + '脥' => ' qiǎn', + '脤' => ' shèn', + '脣' => ' chún', + '脢' => ' méi', + '脡' => ' tǐng', + '脠' => ' shān', + '脟' => ' liè', + '脝' => ' hēng', + '脒' => ' mǐ', + '脜' => ' yǒu', + '脛' => ' jìng', + '脚' => ' jiǎo', + '脙' => ' xiū', + '脘' => ' wǎn', + '脗' => ' wěn', + '脖' => ' bó', + '脕' => ' wàn', + '脔' => ' luán', + '脓' => ' nóng', + '胸' => ' xiōng', + '胶' => ' jiāo', + '脪' => ' xìn', + '胐' => ' kū', + '胚' => ' pēi', + '胙' => ' zuò', + '胘' => ' xián', + '胗' => ' zhēn', + '胖' => ' pàng', + '胕' => ' fǔ', + '胔' => ' zì', + '胓' => ' píng', + '胒' => ' nì', + '胑' => ' zhī', + '胏' => ' zǐ', + '胜' => ' shèng', + '胎' => ' tāi', + '胍' => ' guā', + '背' => ' bèi', + '胋' => ' tián', + '胊' => ' qú', + '胉' => ' bó', + '胈' => ' bá', + '胇' => ' fèi', + '胆' => ' dǎn', + '胅' => ' dié', + '胛' => ' jiǎ', + '胝' => ' zhī', + '胵' => ' chī', + '胪' => ' lú', + '胴' => ' dòng', + '胳' => ' gē', + '胲' => ' hǎi', + '胱' => ' guāng', + '胰' => ' yí', + '胯' => ' kuà', + '胮' => ' pāng', + '胭' => ' yān', + '胬' => ' nǔ', + '胫' => ' jìng', + '胩' => ' kǎ', + '胞' => ' bāo', + '胨' => ' dòng', + '胧' => ' lóng', + '胦' => ' yāng', + '胥' => ' xū', + '胤' => ' yìn', + '胣' => ' chǐ', + '胢' => ' kē', + '胡' => ' hú', + '胠' => ' qū', + '胟' => ' mǔ', + '脩' => ' xiū', + '脫' => ' tuō', + '膒' => ' óu', + '腭' => ' è', + '腷' => ' bì', + '腶' => ' duàn', + '腵' => ' jiā', + '腴' => ' yú', + '腳' => ' jiǎo', + '腲' => ' wěi', + '腱' => ' jiàn', + '腰' => ' yāo', + '腯' => ' tú', + '腮' => ' sāi', + '腬' => ' ròu', + '腹' => ' fù', + '腫' => ' zhǒng', + '腪' => ' yùn', + '腩' => ' nǎn', + '腨' => ' shuàn', + '腧' => ' shù', + '腦' => ' nǎo', + '腥' => ' xīng', + '腤' => ' ān', + '腣' => ' dì', + '腢' => ' ǒu', + '腸' => ' cháng', + '腺' => ' xiàn', + '腠' => ' còu', + '膇' => ' zhuì', + '膑' => ' bìn', + '膐' => ' lǚ', + '膏' => ' gāo', + '膎' => ' xié', + '膍' => ' pí', + '膌' => ' jí', + '膋' => ' liáo', + '膊' => ' bó', + '膉' => ' yì', + '膈' => ' gé', + '膆' => ' sù', + '腻' => ' nì', + '膅' => ' táng', + '膄' => ' sòu', + '膃' => ' wà', + '膂' => ' lǚ', + '膁' => ' qiǎn', + '膀' => ' bǎng', + '腿' => ' tuǐ', + '腾' => ' téng', + '腽' => ' wà', + '腼' => ' miǎn', + '腡' => ' luó', + '腟' => ' chì', + '脬' => ' pāo', + '脸' => ' liǎn', + '腂' => ' lěi', + '腁' => ' pián', + '腀' => ' lún', + '脿' => ' biāo', + '脾' => ' pí', + '脽' => ' shuí', + '脼' => ' liǎng', + '脻' => ' jiē', + '脺' => ' cuì', + '脹' => ' zhàng', + '脷' => ' lì', + '腄' => ' chuí', + '脶' => ' luó', + '脵' => ' gǔ', + '脴' => ' pǐ', + '脳' => ' nao', + '脲' => ' niào', + '脱' => ' tuō', + '脰' => ' dòu', + '脯' => ' pú', + '脮' => ' něi', + '脭' => ' chéng', + '腃' => ' kuì', + '腅' => ' dàn', + '腞' => ' zhuàn', + '腓' => ' féi', + '腝' => ' ní', + '腜' => ' měi', + '腛' => ' wò', + '腚' => ' dìng', + '腙' => ' zōng', + '腘' => ' guó', + '腗' => ' pí', + '腖' => ' dòng', + '腕' => ' wàn', + '腔' => ' qiāng', + '腒' => ' jū', + '腆' => ' tiǎn', + '腑' => ' fǔ', + '腐' => ' fǔ', + '腏' => ' chuò', + '腎' => ' shèn', + '腍' => ' rèn', + '腌' => ' yān', + '腋' => ' yè', + '腊' => ' là', + '腉' => ' nái', + '腈' => ' jīng', + '腇' => ' něi', + '碤' => ' yīng', + '牡' => ' mǔ', + '碢' => ' tuó', + '濬' => ' jùn', + '濶' => ' kuò', + '濵' => ' bin', + '濴' => ' yíng', + '濳' => ' qián', + '濲' => ' gǔ', + '濱' => ' bīn', + '濰' => ' wéi', + '濯' => ' zhuó', + '濮' => ' pú', + '濭' => ' ǎi', + '濫' => ' làn', + '濸' => ' cang', + '濪' => ' jìng', + '濩' => ' huò', + '濨' => ' cí', + '濧' => ' duì', + '濦' => ' yǐn', + '濥' => ' yǐn', + '濤' => ' tāo', + '濣' => ' wò', + '濢' => ' cuì', + '濡' => ' rú', + '濷' => ' fèi', + '濹' => ' me', + '濟' => ' jì', + '瀆' => ' dú', + '瀐' => ' jiān', + '瀏' => ' liú', + '瀎' => ' mò', + '瀍' => ' chán', + '瀌' => ' biāo', + '瀋' => ' shěn', + '瀊' => ' pán', + '瀉' => ' xiè', + '瀈' => ' huī', + '瀇' => ' wǎng', + '瀅' => ' yíng', + '濺' => ' jiàn', + '瀄' => ' zhì', + '瀃' => ' sì', + '瀂' => ' lǔ', + '瀁' => ' yàng', + '瀀' => ' yōu', + '濿' => ' lì', + '濾' => ' lǜ', + '濽' => ' zàn', + '濼' => ' luò', + '濻' => ' wěi', + '濠' => ' háo', + '濞' => ' bì', + '瀒' => ' sè', + '澸' => ' dǎn', + '濂' => ' lián', + '濁' => ' zhuó', + '激' => ' jī', + '澿' => ' qín', + '澾' => ' tà', + '澽' => ' jù', + '澼' => ' pì', + '澻' => ' suì', + '澺' => ' yì', + '澹' => ' dàn', + '澷' => ' màn', + '濄' => ' guō', + '澶' => ' chán', + '澵' => ' zhēn', + '澴' => ' huán', + '澳' => ' ào', + '澲' => ' yè', + '澱' => ' diàn', + '澰' => ' liàn', + '澯' => ' càn', + '澮' => ' huì', + '澭' => ' yōng', + '濃' => ' nóng', + '濅' => ' jìn', + '濝' => ' qí', + '濒' => ' bīn', + '濜' => ' jìn', + '濛' => ' méng', + '濚' => ' yíng', + '濙' => ' yíng', + '濘' => ' nìng', + '濗' => ' mì', + '濖' => ' shù', + '濕' => ' shī', + '濔' => ' mǐ', + '濓' => ' lián', + '濑' => ' lài', + '濆' => ' fén', + '濐' => ' zhǔ', + '濏' => ' sè', + '濎' => ' dǐng', + '濍' => ' sōng', + '濌' => ' tà', + '濋' => ' chǔ', + '濊' => ' huì', + '濉' => ' suī', + '濈' => ' jí', + '濇' => ' sè', + '瀑' => ' pù', + '瀓' => ' chéng', + '澫' => ' wàn', + '灔' => ' yàn', + '灞' => ' bà', + '灝' => ' hào', + '灜' => ' ying', + '灛' => ' chǎn', + '灚' => ' jiǎo', + '灙' => ' dǎng', + '灘' => ' tān', + '灗' => ' shàn', + '灖' => ' mǐ', + '灕' => ' lí', + '灓' => ' luán', + '灠' => ' lǎn', + '灒' => ' zàn', + '灑' => ' sǎ', + '灐' => ' ying', + '灏' => ' hào', + '灎' => ' yàn', + '灍' => ' què', + '灌' => ' guàn', + '灋' => ' fǎ', + '灊' => ' qián', + '灉' => ' yōng', + '灟' => ' zhú', + '灡' => ' lán', + '灇' => ' cóng', + '灮' => ' guāng', + '灸' => ' jiǔ', + '灷' => ' zhuàn', + '灶' => ' zào', + '灵' => ' líng', + '灴' => ' hōng', + '灳' => ' hui', + '灲' => ' xiāo', + '灱' => ' xiāo', + '灰' => ' huī', + '灯' => ' dēng', + '灭' => ' miè', + '灢' => ' nǎng', + '灬' => ' biāo', + '火' => ' huǒ', + '灪' => ' yù', + '灩' => ' yàn', + '灨' => ' gàn', + '灧' => ' yàn', + '灦' => ' xiǎn', + '灥' => ' xún', + '灤' => ' luán', + '灣' => ' wān', + '灈' => ' qú', + '灆' => ' lán', + '瀔' => ' gǔ', + '瀠' => ' yíng', + '瀪' => ' fán', + '瀩' => ' duì', + '瀨' => ' lài', + '瀧' => ' lóng', + '瀦' => ' zhū', + '瀥' => ' xuè', + '瀤' => ' huái', + '瀣' => ' xiè', + '瀢' => ' wěi', + '瀡' => ' suǐ', + '瀟' => ' xiāo', + '瀬' => ' lài', + '瀞' => ' jìng', + '瀝' => ' lì', + '瀜' => ' róng', + '瀛' => ' yíng', + '瀚' => ' hàn', + '瀙' => ' qìn', + '瀘' => ' lú', + '瀗' => ' xiàn', + '瀖' => ' huò', + '瀕' => ' bīn', + '瀫' => ' hú', + '瀭' => ' shu', + '灅' => ' lěi', + '瀺' => ' chán', + '灄' => ' shè', + '灃' => ' fēng', + '灂' => ' zhuó', + '灁' => ' yuān', + '灀' => ' shuàng', + '瀿' => ' fán', + '瀾' => ' lán', + '瀽' => ' jiǎn', + '瀼' => ' ráng', + '瀻' => ' dài', + '瀹' => ' yuè', + '瀮' => ' ling', + '瀸' => ' jiān', + '瀷' => ' yì', + '瀶' => ' lín', + '瀵' => ' fèn', + '瀴' => ' yíng', + '瀳' => ' jiàn', + '瀲' => ' liàn', + '瀱' => ' jì', + '瀰' => ' mí', + '瀯' => ' yíng', + '澬' => ' zī', + '澪' => ' líng', + '灺' => ' xiè', + '漜' => ' yě', + '漦' => ' chí', + '漥' => ' wā', + '漤' => ' lǎn', + '漣' => ' lián', + '漢' => ' hàn', + '漡' => ' shāng', + '漠' => ' mò', + '漟' => ' táng', + '漞' => ' mì', + '漝' => ' xí', + '漛' => ' téng', + '漨' => ' féng', + '漚' => ' ōu', + '漙' => ' tuán', + '漘' => ' chún', + '漗' => ' cōng', + '漖' => ' jiào', + '漕' => ' cáo', + '演' => ' yǎn', + '漓' => ' lí', + '漒' => ' qiáng', + '漑' => ' gài', + '漧' => ' gān', + '漩' => ' xuán', + '漏' => ' lòu', + '漶' => ' huàn', + '潀' => ' cóng', + '漿' => ' jiāng', + '漾' => ' yàng', + '漽' => ' tí', + '漼' => ' cuǐ', + '漻' => ' liáo', + '漺' => ' shuǎng', + '漹' => ' yān', + '漸' => ' jiàn', + '漷' => ' huǒ', + '漵' => ' xù', + '漪' => ' yī', + '漴' => ' zhuàng', + '漳' => ' zhāng', + '漲' => ' zhǎng', + '漱' => ' shù', + '漰' => ' pēng', + '漯' => ' luò', + '漮' => ' kāng', + '漭' => ' mǎng', + '漬' => ' zì', + '漫' => ' màn', + '漐' => ' zhí', + '漎' => ' cóng', + '潂' => ' hóng', + '滨' => ' bīn', + '滲' => ' shèn', + '滱' => ' kòu', + '滰' => ' jiàng', + '滯' => ' zhì', + '滮' => ' biāo', + '滭' => ' bì', + '滬' => ' hù', + '滫' => ' xiǔ', + '滪' => ' yù', + '滩' => ' tān', + '滧' => ' xiao', + '滴' => ' dī', + '滦' => ' luán', + '滥' => ' làn', + '滤' => ' lǜ', + '滣' => ' chún', + '滢' => ' yíng', + '满' => ' mǎn', + '滠' => ' shè', + '滟' => ' yàn', + '滞' => ' zhì', + '滝' => ' lóng', + '滳' => ' shāng', + '滵' => ' mì', + '漍' => ' guó', + '漂' => ' piào', + '漌' => ' jǐn', + '漋' => ' lóng', + '漊' => ' lóu', + '漉' => ' lù', + '漈' => ' jì', + '漇' => ' xǐ', + '漆' => ' qī', + '漅' => ' cháo', + '漄' => ' yá', + '漃' => ' jì', + '漁' => ' yú', + '滶' => ' áo', + '漀' => ' qǐng', + '滿' => ' mǎn', + '滾' => ' gǔn', + '滽' => ' yōng', + '滼' => ' fàn', + '滻' => ' chǎn', + '滺' => ' yōu', + '滹' => ' hū', + '滸' => ' hǔ', + '滷' => ' lǔ', + '潁' => ' yǐng', + '潃' => ' xún', + '澩' => ' xué', + '澄' => ' chéng', + '澎' => ' pēng', + '澍' => ' shù', + '澌' => ' sī', + '澋' => ' hòng', + '澊' => ' cūn', + '澉' => ' gǎn', + '澈' => ' chè', + '澇' => ' lào', + '澆' => ' jiāo', + '澅' => ' huà', + '澃' => ' jiǒng', + '澐' => ' yún', + '澂' => ' chéng', + '澁' => ' sè', + '澀' => ' sè', + '潿' => ' wéi', + '潾' => ' lín', + '潽' => ' pū', + '潼' => ' tóng', + '潻' => ' shǔ', + '潺' => ' chán', + '潹' => ' chán', + '澏' => ' hán', + '澑' => ' liù', + '潷' => ' bì', + '澞' => ' yú', + '澨' => ' shì', + '澧' => ' lǐ', + '澦' => ' yù', + '澥' => ' xiè', + '澤' => ' zé', + '澣' => ' huàn', + '澢' => ' dāng', + '澡' => ' zǎo', + '澠' => ' miǎn', + '澟' => ' lǐn', + '澝' => ' ning', + '澒' => ' hòng', + '澜' => ' lán', + '澛' => ' lǔ', + '澚' => ' yu', + '澙' => ' xì', + '澘' => ' shān', + '澗' => ' jiàn', + '澖' => ' xián', + '澕' => ' hé', + '澔' => ' hào', + '澓' => ' fú', + '潸' => ' shān', + '潶' => ' hēi', + '潄' => ' shù', + '潐' => ' jiào', + '潚' => ' sù', + '潙' => ' wéi', + '潘' => ' pān', + '潗' => ' jí', + '潖' => ' pá', + '潕' => ' wǔ', + '潔' => ' jié', + '潓' => ' huì', + '潒' => ' dàng', + '潑' => ' pō', + '潏' => ' yù', + '潜' => ' qián', + '潎' => ' pì', + '潍' => ' wéi', + '潌' => ' zhì', + '潋' => ' liàn', + '潊' => ' xù', + '潉' => ' kun', + '潈' => ' zong', + '潇' => ' xiāo', + '潆' => ' yíng', + '潅' => ' guàn', + '潛' => ' qián', + '潝' => ' xī', + '潵' => ' sǎ', + '潪' => ' zhè', + '潴' => ' zhū', + '潳' => ' tú', + '潲' => ' shào', + '潱' => ' yē', + '潰' => ' kuì', + '潯' => ' xún', + '潮' => ' cháo', + '潭' => ' tán', + '潬' => ' shàn', + '潫' => ' wān', + '潩' => ' yì', + '潞' => ' lù', + '潨' => ' cóng', + '潧' => ' zhēn', + '潦' => ' lǎo', + '潥' => ' sù', + '潤' => ' rùn', + '潣' => ' mǐn', + '潢' => ' huáng', + '潡' => ' dùn', + '潠' => ' xùn', + '潟' => ' xì', + '灹' => ' zhà', + '灻' => ' chì', + '滛' => ' yín', + '熍' => ' qiong', + '熗' => ' qiàng', + '熖' => ' yan', + '熕' => ' gōng', + '熔' => ' róng', + '熓' => ' wǔ', + '熒' => ' yíng', + '熑' => ' lián', + '熐' => ' mì', + '熏' => ' xūn', + '熎' => ' yào', + '熌' => ' shǎn', + '熙' => ' xī', + '熋' => ' nái', + '熊' => ' xióng', + '熉' => ' yún', + '熈' => ' xī', + '熇' => ' hè', + '熆' => ' hé', + '熅' => ' yùn', + '熄' => ' xī', + '熃' => ' wù', + '熂' => ' xì', + '熘' => ' liū', + '熚' => ' bì', + '熀' => ' huǎng', + '熧' => ' zōng', + '熱' => ' rè', + '熰' => ' ōu', + '熯' => ' hàn', + '熮' => ' liǔ', + '熭' => ' wèi', + '熬' => ' áo', + '熫' => ' zhì', + '熪' => ' yí', + '熩' => ' hù', + '熨' => ' yùn', + '熦' => ' jué', + '熛' => ' biāo', + '熥' => ' tēng', + '熤' => ' yì', + '熣' => ' suī', + '熢' => ' péng', + '熡' => ' lóu', + '熠' => ' yì', + '熟' => ' shú', + '熞' => ' jiān', + '熝' => ' lù', + '熜' => ' cōng', + '熁' => ' xié', + '煿' => ' bó', + '熳' => ' màn', + '煙' => ' yān', + '煣' => ' róu', + '煢' => ' qióng', + '煡' => ' xìn', + '煠' => ' zhá', + '煟' => ' wèi', + '煞' => ' shā', + '煝' => ' mèi', + '煜' => ' yù', + '煛' => ' jiǒng', + '煚' => ' jiǒng', + '煘' => ' chán', + '煥' => ' huàn', + '煗' => ' nuǎn', + '煖' => ' nuǎn', + '煕' => ' xī', + '煔' => ' shǎn', + '煓' => ' tuān', + '煒' => ' wěi', + '煑' => ' zhǔ', + '煐' => ' yīng', + '煏' => ' bì', + '煎' => ' jiān', + '煤' => ' méi', + '煦' => ' xù', + '煾' => ' ēn', + '煳' => ' hú', + '煽' => ' shān', + '煼' => ' chǎo', + '煻' => ' táng', + '煺' => ' tuì', + '煹' => ' gòu', + '煸' => ' biān', + '煷' => ' liang', + '煶' => ' shi', + '煵' => ' xiā', + '煴' => ' yūn', + '煲' => ' bāo', + '照' => ' zhào', + '煱' => ' guā', + '煰' => ' gào', + '煯' => ' jiē', + '煮' => ' zhǔ', + '煭' => ' liè', + '煬' => ' yáng', + '煫' => ' suì', + '煪' => ' qiú', + '煩' => ' fán', + '煨' => ' wēi', + '熲' => ' jiǒng', + '熴' => ' kun', + '煌' => ' huáng', + '燵' => ' da', + '燿' => ' yào', + '燾' => ' dào', + '燽' => ' chóu', + '燼' => ' jìn', + '燻' => ' xūn', + '燺' => ' kǎo', + '燹' => ' xiǎn', + '燸' => ' rú', + '燷' => ' lán', + '燶' => ' nóng', + '燴' => ' huì', + '爁' => ' làn', + '燳' => ' zhào', + '燲' => ' xié', + '燱' => ' yì', + '燰' => ' wēi', + '燯' => ' líng', + '燮' => ' xiè', + '燭' => ' zhú', + '燬' => ' huǐ', + '燫' => ' lián', + '燪' => ' cōng', + '爀' => ' hè', + '爂' => ' biāo', + '燨' => ' xī', + '爏' => ' lì', + '爙' => ' rǎng', + '爘' => ' can', + '爗' => ' yè', + '爖' => ' lóng', + '爕' => ' xiè', + '爔' => ' xī', + '爓' => ' yàn', + '爒' => ' liǎo', + '爑' => ' jué', + '爐' => ' lú', + '爎' => ' liao', + '爃' => ' róng', + '爍' => ' shuò', + '爌' => ' kuàng', + '爋' => ' xùn', + '爊' => ' āo', + '爉' => ' là', + '爈' => ' lǜ', + '爇' => ' ruò', + '爆' => ' bào', + '爅' => ' mò', + '爄' => ' lì', + '燩' => ' què', + '燧' => ' suì', + '熵' => ' shāng', + '燁' => ' yè', + '燋' => ' jiāo', + '燊' => ' shēn', + '燉' => ' dùn', + '燈' => ' dēng', + '燇' => ' jùn', + '燆' => ' qiāo', + '燅' => ' xián', + '燄' => ' yàn', + '燃' => ' rán', + '燂' => ' tán', + '燀' => ' chǎn', + '燍' => ' sī', + '熿' => ' huáng', + '熾' => ' chì', + '熽' => ' xiào', + '熼' => ' yì', + '熻' => ' xī', + '熺' => ' xī', + '熹' => ' xī', + '熸' => ' jiān', + '熷' => ' zēng', + '熶' => ' cuàn', + '燌' => ' fén', + '燎' => ' liáo', + '燦' => ' càn', + '燛' => ' jǐng', + '燥' => ' zào', + '燤' => ' tài', + '燣' => ' lán', + '燢' => ' xué', + '燡' => ' yì', + '燠' => ' yù', + '營' => ' yíng', + '燞' => ' jiǎo', + '燝' => ' jing', + '燜' => ' mèn', + '燚' => ' yì', + '燏' => ' yù', + '燙' => ' tàng', + '燘' => ' měi', + '燗' => ' làn', + '燖' => ' xún', + '燕' => ' yàn', + '燔' => ' fán', + '燓' => ' fēn', + '燒' => ' shāo', + '燑' => ' tóng', + '燐' => ' lín', + '煍' => ' jiǎo', + '煋' => ' xīng', + '灼' => ' zhuó', + '炼' => ' liàn', + '烆' => ' héng', + '烅' => ' xù', + '烄' => ' jiǎo', + '烃' => ' tīng', + '烂' => ' làn', + '烁' => ' shuò', + '烀' => ' hū', + '炿' => ' zhou', + '炾' => ' huǎng', + '炽' => ' chì', + '炻' => ' shí', + '烈' => ' liè', + '為' => ' wèi', + '点' => ' diǎn', + '炸' => ' zhà', + '炷' => ' zhù', + '炶' => ' hān', + '炵' => ' tōng', + '炴' => ' yǎng', + '炳' => ' bǐng', + '炲' => ' tái', + '炱' => ' tái', + '烇' => ' quǎn', + '烉' => ' huàn', + '炯' => ' jiǒng', + '烖' => ' zāi', + '烠' => ' huí', + '烟' => ' yān', + '烞' => ' pò', + '烝' => ' zhēng', + '烜' => ' xuǎn', + '烛' => ' zhú', + '烚' => ' xiá', + '烙' => ' lào', + '烘' => ' hōng', + '烗' => ' kài', + '烕' => ' miè', + '烊' => ' yáng', + '烔' => ' tóng', + '烓' => ' wēi', + '烒' => ' shì', + '烑' => ' yáo', + '烐' => ' zhōu', + '烏' => ' wū', + '烎' => ' yín', + '烍' => ' xiǎn', + '烌' => ' xiū', + '烋' => ' xiū', + '炰' => ' páo', + '炮' => ' pào', + '烢' => ' chè', + '炈' => ' yì', + '炒' => ' chǎo', + '炑' => ' mù', + '炐' => ' pàng', + '炏' => ' kài', + '炎' => ' yán', + '炍' => ' pàn', + '炌' => ' kài', + '炋' => ' pī', + '炊' => ' chuī', + '炉' => ' lú', + '炇' => ' pò', + '炔' => ' guì', + '炆' => ' wén', + '炅' => ' jiǒng', + '炄' => ' niǔ', + '炃' => ' fén', + '炂' => ' zhōng', + '炁' => ' qì', + '炀' => ' yáng', + '灿' => ' càn', + '灾' => ' zāi', + '災' => ' zāi', + '炓' => ' liào', + '炕' => ' kàng', + '炭' => ' tàn', + '炢' => ' zhú', + '炬' => ' jù', + '炫' => ' xuàn', + '炪' => ' zhuō', + '炩' => ' lìng', + '炨' => ' duò', + '炧' => ' xiè', + '炦' => ' bá', + '炥' => ' fú', + '炤' => ' zhào', + '炣' => ' kě', + '炡' => ' zhēng', + '炖' => ' dùn', + '炠' => ' xiá', + '炟' => ' dá', + '炞' => ' bian', + '炝' => ' qiàng', + '炜' => ' wěi', + '炛' => ' guāng', + '炚' => ' guāng', + '炙' => ' zhì', + '炘' => ' xīn', + '炗' => ' guāng', + '烡' => ' guāng', + '烣' => ' huī', + '煊' => ' xuān', + '焥' => ' wò', + '焯' => ' chāo', + '焮' => ' xìn', + '焭' => ' qióng', + '焬' => ' xī', + '焫' => ' ruò', + '焪' => ' qióng', + '焩' => ' píng', + '焨' => ' fèng', + '焧' => ' cōng', + '焦' => ' jiāo', + '焤' => ' fǔ', + '焱' => ' yàn', + '焣' => ' chǎo', + '焢' => ' hōng', + '無' => ' wú', + '焠' => ' cuì', + '焟' => ' xī', + '焞' => ' tūn', + '焝' => ' hùn', + '焜' => ' kūn', + '焛' => ' lìn', + '焚' => ' fén', + '焰' => ' yàn', + '焲' => ' yì', + '焘' => ' dào', + '焿' => ' gēng', + '煉' => ' liàn', + '煈' => ' fèng', + '煇' => ' huī', + '煆' => ' xiā', + '煅' => ' duàn', + '煄' => ' zhǒng', + '煃' => ' kuǐ', + '煂' => ' hè', + '煁' => ' chén', + '煀' => ' wei', + '焾' => ' niǎn', + '焳' => ' jué', + '焽' => ' xiǒng', + '焼' => ' shāo', + '焻' => ' chàng', + '焺' => ' shēng', + '焹' => ' wang', + '焸' => ' xiòng', + '焷' => ' pí', + '然' => ' rán', + '焵' => ' gàng', + '焴' => ' yù', + '焙' => ' bèi', + '焗' => ' jú', + '烤' => ' kǎo', + '烱' => ' jiǒng', + '烻' => ' yàn', + '烺' => ' lǎng', + '烹' => ' pēng', + '烸' => ' hǎi', + '烷' => ' wán', + '烶' => ' tǐng', + '烵' => ' zhuó', + '烴' => ' tīng', + '烳' => ' pǔ', + '烲' => ' xiè', + '烰' => ' fú', + '烽' => ' fēng', + '烯' => ' xī', + '烮' => ' lie', + '热' => ' rè', + '烬' => ' jìn', + '烫' => ' tàng', + '烩' => ' huì', + '烨' => ' yè', + '烧' => ' shāo', + '烦' => ' fán', + '烥' => ' chen', + '烼' => ' xù', + '烾' => ' chì', + '焖' => ' mèn', + '焋' => ' zhuàng', + '焕' => ' huàn', + '焔' => ' yàn', + '焓' => ' hán', + '焒' => ' lü', + '焑' => ' yān', + '焐' => ' wù', + '焏' => ' jí', + '焎' => ' xiè', + '焍' => ' dì', + '焌' => ' jùn', + '焊' => ' hàn', + '烿' => ' róng', + '焉' => ' yān', + '焈' => ' xī', + '焇' => ' xiāo', + '焆' => ' juān', + '焅' => ' kù', + '焄' => ' xūn', + '焃' => ' hè', + '焂' => ' shū', + '焁' => ' xī', + '焀' => ' hú', + '滜' => ' gāo', + '滚' => ' gǔn', + '爛' => ' làn', + '沫' => ' mò', + '沵' => ' mǐ', + '沴' => ' lì', + '河' => ' hé', + '沲' => ' tuó', + '沱' => ' tuó', + '沰' => ' tuō', + '沯' => ' zǎn', + '沮' => ' jǔ', + '沭' => ' shù', + '沬' => ' mèi', + '沪' => ' hù', + '沷' => ' fā', + '沩' => ' wéi', + '沨' => ' fēng', + '沧' => ' cāng', + '沦' => ' lún', + '沥' => ' lì', + '沤' => ' ōu', + '沣' => ' fēng', + '沢' => ' zé', + '没' => ' méi', + '沠' => ' liú', + '沶' => ' yí', + '沸' => ' fèi', + '沞' => ' zā', + '泅' => ' qiú', + '泏' => ' zhú', + '泎' => ' zé', + '泍' => ' bēn', + '泌' => ' mì', + '泋' => ' huì', + '泊' => ' pō', + '泉' => ' quán', + '泈' => ' zhōng', + '泇' => ' jiā', + '泆' => ' yì', + '泄' => ' xiè', + '油' => ' yóu', + '泃' => ' jū', + '泂' => ' jiǒng', + '況' => ' kuàng', + '泀' => ' sī', + '沿' => ' yán', + '沾' => ' zhān', + '沽' => ' gū', + '沼' => ' zhǎo', + '治' => ' zhì', + '沺' => ' tián', + '沟' => ' gōu', + '沝' => ' zhuǐ', + '泑' => ' yōu', + '汷' => ' zhōng', + '沁' => ' qìn', + '沀' => ' xù', + '汿' => ' xù', + '汾' => ' fén', + '汽' => ' qì', + '汼' => ' niú', + '汻' => ' hǔ', + '決' => ' jué', + '汹' => ' xiōng', + '汸' => ' fāng', + '汶' => ' wèn', + '沃' => ' wò', + '汵' => ' gàn', + '汴' => ' biàn', + '汳' => ' biàn', + '汲' => ' jí', + '汱' => ' quǎn', + '汰' => ' tài', + '汯' => ' hóng', + '汮' => ' jūn', + '汭' => ' ruì', + '汬' => ' jǐng', + '沂' => ' yí', + '沄' => ' yún', + '沜' => ' pàn', + '沑' => ' nǜ', + '沛' => ' pèi', + '沚' => ' zhǐ', + '沙' => ' shā', + '沘' => ' bǐ', + '沗' => ' pāng', + '沖' => ' chōng', + '沕' => ' mì', + '沔' => ' miǎn', + '沓' => ' dá', + '沒' => ' méi', + '沐' => ' mù', + '沅' => ' yuán', + '沏' => ' qī', + '沎' => ' huò', + '沍' => ' hù', + '沌' => ' dùn', + '沋' => ' yóu', + '沊' => ' dàn', + '沉' => ' chén', + '沈' => ' shěn', + '沇' => ' yǎn', + '沆' => ' hàng', + '泐' => ' lè', + '泒' => ' gū', + '汪' => ' wāng', + '洓' => ' sè', + '洝' => ' àn', + '洜' => ' luò', + '洛' => ' luò', + '洚' => ' jiàng', + '洙' => ' zhū', + '洘' => ' kǎo', + '洗' => ' xǐ', + '洖' => ' wú', + '洕' => ' yìn', + '洔' => ' zhǐ', + '洒' => ' sǎ', + '洟' => ' tì', + '洑' => ' fú', + '洐' => ' xíng', + '洏' => ' ér', + '洎' => ' jì', + '洍' => ' sì', + '洌' => ' liè', + '洋' => ' yáng', + '洊' => ' jiàn', + '洉' => ' hòu', + '洈' => ' wéi', + '洞' => ' dòng', + '洠' => ' móu', + '洆' => ' chéng', + '洭' => ' kuāng', + '洷' => ' zhì', + '洶' => ' xiōng', + '洵' => ' xún', + '洴' => ' píng', + '洳' => ' rù', + '洲' => ' zhōu', + '洱' => ' ěr', + '洰' => ' jù', + '洯' => ' qiè', + '洮' => ' táo', + '洬' => ' sù', + '洡' => ' lèi', + '洫' => ' xù', + '洪' => ' hóng', + '洩' => ' xiè', + '洨' => ' xiáo', + '洧' => ' wěi', + '洦' => ' pò', + '津' => ' jīn', + '洤' => ' quán', + '洣' => ' mǐ', + '洢' => ' yī', + '洇' => ' yīn', + '洅' => ' zài', + '泓' => ' hóng', + '泟' => ' chēng', + '泩' => ' shēng', + '注' => ' zhù', + '泧' => ' sà', + '泦' => ' jú', + '泥' => ' ní', + '泤' => ' sì', + '泣' => ' qì', + '波' => ' bō', + '泡' => ' pào', + '泠' => ' líng', + '泞' => ' nìng', + '泫' => ' xuàn', + '泝' => ' sù', + '泜' => ' zhī', + '泛' => ' fàn', + '泚' => ' cǐ', + '泙' => ' píng', + '泘' => ' hū', + '泗' => ' sì', + '泖' => ' mǎo', + '法' => ' fǎ', + '泔' => ' gān', + '泪' => ' lèi', + '泬' => ' jué', + '洄' => ' huí', + '泹' => ' dàn', + '洃' => ' huī', + '洂' => ' yì', + '洁' => ' jié', + '洀' => ' pán', + '泿' => ' yín', + '泾' => ' jīng', + '泽' => ' zé', + '泼' => ' pō', + '泻' => ' xiè', + '泺' => ' luò', + '泸' => ' lú', + '泭' => ' fú', + '泷' => ' lóng', + '泶' => ' xué', + '泵' => ' bèng', + '泴' => ' guàn', + '泳' => ' yǒng', + '泲' => ' jǐ', + '泱' => ' yāng', + '泰' => ' tài', + '泯' => ' mǐn', + '泮' => ' pàn', + '汫' => ' jǐng', + '汩' => ' gǔ', + '洹' => ' huán', + '毛' => ' máo', + '毥' => ' xún', + '毤' => ' tuò', + '毣' => ' mù', + '毢' => ' sāi', + '毡' => ' zhān', + '毠' => ' jiā', + '毟' => ' lie', + '毞' => ' pí', + '毝' => ' cǎi', + '毜' => ' háo', + '毚' => ' chán', + '毧' => ' róng', + '毙' => ' bì', + '毘' => ' pí', + '毗' => ' pí', + '毖' => ' bì', + '毕' => ' bì', + '比' => ' bǐ', + '毓' => ' yù', + '毒' => ' dú', + '毑' => ' jiě', + '毐' => ' ǎi', + '毦' => ' ěr', + '毨' => ' xiǎn', + '毎' => ' měi', + '毵' => ' sān', + '毿' => ' sān', + '毾' => ' tà', + '毽' => ' jiàn', + '毼' => ' hé', + '毻' => ' tuò', + '毺' => ' yū', + '毹' => ' shū', + '毸' => ' sāi', + '毷' => ' mào', + '毶' => ' san', + '毴' => ' bī', + '毩' => ' jú', + '毳' => ' cuì', + '毲' => ' duō', + '毱' => ' jú', + '毰' => ' péi', + '毯' => ' tǎn', + '毮' => ' shā', + '毭' => ' dòu', + '毬' => ' qiú', + '毫' => ' háo', + '毪' => ' mú', + '每' => ' měi', + '母' => ' mǔ', + '氁' => ' mú', + '殧' => ' jiù', + '殱' => ' jian', + '殰' => ' dú', + '殯' => ' bìn', + '殮' => ' liàn', + '殭' => ' jiāng', + '殬' => ' dù', + '殫' => ' dān', + '殪' => ' yì', + '殩' => ' cuàn', + '殨' => ' huì', + '殦' => ' diāo', + '殳' => ' shū', + '殥' => ' yín', + '殤' => ' shāng', + '殣' => ' jìn', + '殢' => ' tì', + '殡' => ' bìn', + '殠' => ' chòu', + '殟' => ' wēn', + '殞' => ' yǔn', + '殝' => ' zhēn', + '殜' => ' dié', + '殲' => ' jiān', + '殴' => ' ōu', + '毌' => ' guàn', + '毁' => ' huǐ', + '毋' => ' wú', + '毊' => ' xiāo', + '毉' => ' yī', + '毈' => ' duàn', + '毇' => ' huǐ', + '毆' => ' ōu', + '毅' => ' yì', + '毄' => ' jī', + '毃' => ' qiāo', + '毂' => ' gǔ', + '毀' => ' huǐ', + '段' => ' duàn', + '殿' => ' diàn', + '殾' => ' xùn', + '殽' => ' xiáo', + '殼' => ' ké', + '殻' => ' qiào', + '殺' => ' shā', + '殹' => ' yì', + '殸' => ' qìng', + '殷' => ' yīn', + '殶' => ' zhù', + '氀' => ' lǘ', + '氂' => ' máo', + '汨' => ' mì', + '汃' => ' bīn', + '汍' => ' wán', + '汌' => ' chuàn', + '汋' => ' zhuó', + '汊' => ' chà', + '汉' => ' hàn', + '汈' => ' diāo', + '汇' => ' huì', + '汆' => ' cuān', + '汅' => ' miǎn', + '汄' => ' zè', + '求' => ' qiú', + '汏' => ' dà', + '汁' => ' zhī', + '汀' => ' tīng', + '氿' => ' guǐ', + '氾' => ' fàn', + '氽' => ' tǔn', + '氼' => ' nì', + '氻' => ' lè', + '氺' => ' shui', + '氹' => ' dàng', + '永' => ' yǒng', + '汎' => ' fàn', + '汐' => ' xī', + '氶' => ' zhěng', + '汝' => ' rǔ', + '汧' => ' qiān', + '汦' => ' zhǐ', + '汥' => ' zhī', + '汤' => ' tāng', + '汣' => ' jiu', + '汢' => ' tu', + '污' => ' wū', + '池' => ' chí', + '江' => ' jiāng', + '汞' => ' gǒng', + '汜' => ' sì', + '汑' => ' tuō', + '汛' => ' xùn', + '汚' => ' wū', + '汙' => ' wū', + '汘' => ' qiān', + '汗' => ' hàn', + '汖' => ' pìn', + '汕' => ' shàn', + '汔' => ' qì', + '汓' => ' qiú', + '汒' => ' máng', + '氷' => ' bīng', + '氵' => ' shui', + '氃' => ' tóng', + '氏' => ' shì', + '氙' => ' xiān', + '氘' => ' dāo', + '気' => ' qì', + '氖' => ' nǎi', + '氕' => ' piē', + '气' => ' qì', + '氓' => ' máng', + '氒' => ' jué', + '民' => ' mín', + '氐' => ' dī', + '氎' => ' dié', + '氛' => ' fēn', + '氍' => ' qú', + '氌' => ' lǔ', + '氋' => ' méng', + '氊' => ' zhān', + '氉' => ' sào', + '氈' => ' zhān', + '氇' => ' lu', + '氆' => ' pǔ', + '氅' => ' chǎng', + '氄' => ' rǒng', + '氚' => ' chuān', + '氜' => ' yáng', + '水' => ' shuǐ', + '氩' => ' yà', + '氳' => ' yūn', + '氲' => ' yūn', + '氱' => ' yǎng', + '氰' => ' qíng', + '氯' => ' lǜ', + '氮' => ' dàn', + '氭' => ' dōng', + '氬' => ' yà', + '氫' => ' qīng', + '氪' => ' kè', + '氨' => ' ān', + '氝' => ' nèi', + '氧' => ' yǎng', + '氦' => ' hài', + '氥' => ' xī', + '氤' => ' yīn', + '氣' => ' qì', + '氢' => ' qīng', + '氡' => ' dōng', + '氠' => ' shēn', + '氟' => ' fú', + '氞' => ' bin', + '洸' => ' guāng', + '洺' => ' míng', + '滙' => ' huì', + '湌' => ' cān', + '湖' => ' hú', + '湕' => ' jiǎn', + '湔' => ' jiān', + '湓' => ' pén', + '湒' => ' jí', + '湑' => ' xū', + '湐' => ' mò', + '湏' => ' huì', + '湎' => ' miǎn', + '湍' => ' tuān', + '湋' => ' wéi', + '湘' => ' xiāng', + '湊' => ' còu', + '湉' => ' tián', + '湈' => ' méi', + '湇' => ' qì', + '湆' => ' qì', + '湅' => ' liàn', + '湄' => ' méi', + '湃' => ' pài', + '湂' => ' è', + '湁' => ' chì', + '湗' => ' fèng', + '湙' => ' yì', + '渿' => ' nài', + '湦' => ' shēng', + '湰' => ' lóng', + '湯' => ' tāng', + '湮' => ' yān', + '湭' => ' qiú', + '湬' => ' jiǎo', + '湫' => ' jiǎo', + '湪' => ' tuàn', + '湩' => ' dòng', + '湨' => ' jú', + '湧' => ' yǒng', + '湥' => ' tū', + '湚' => ' yìn', + '湤' => ' shī', + '湣' => ' mǐn', + '湢' => ' bì', + '湡' => ' yú', + '湠' => ' tàn', + '湟' => ' huáng', + '湞' => ' chēng', + '湝' => ' jiē', + '湜' => ' shí', + '湛' => ' zhàn', + '湀' => ' guǐ', + '渾' => ' hún', + '湲' => ' yuán', + '渘' => ' róu', + '渢' => ' fán', + '渡' => ' dù', + '渠' => ' qú', + '渟' => ' tíng', + '渞' => ' qiú', + '渝' => ' yú', + '渜' => ' nuǎn', + '減' => ' jiǎn', + '渚' => ' zhǔ', + '渙' => ' huàn', + '渗' => ' shèn', + '渤' => ' bó', + '渖' => ' shěn', + '渕' => ' yuān', + '渔' => ' yú', + '渓' => ' xi', + '渒' => ' pì', + '渑' => ' miǎn', + '渐' => ' jiàn', + '渏' => ' qi', + '渎' => ' dú', + '渍' => ' zì', + '渣' => ' zhā', + '渥' => ' wò', + '渽' => ' zāi', + '渲' => ' xuàn', + '渼' => ' měi', + '渻' => ' shěng', + '渺' => ' miǎo', + '渹' => ' hōng', + '游' => ' yóu', + '渷' => ' yǎn', + '渶' => ' yīng', + '渵' => ' máo', + '渴' => ' kě', + '渳' => ' mǐ', + '渱' => ' hóng', + '渦' => ' wō', + '渰' => ' yǎn', + '港' => ' gǎng', + '渮' => ' hé', + '渭' => ' wèi', + '測' => ' cè', + '渫' => ' xiè', + '渪' => ' rú', + '温' => ' wēn', + '渨' => ' wēi', + '渧' => ' dì', + '湱' => ' huò', + '湳' => ' nǎn', + '渋' => ' se', + '溴' => ' xiù', + '溾' => ' āi', + '溽' => ' rù', + '溼' => ' shī', + '溻' => ' tā', + '溺' => ' nì', + '溹' => ' suò', + '溸' => ' sù', + '溷' => ' hùn', + '溶' => ' róng', + '溵' => ' yīn', + '溳' => ' yún', + '滀' => ' chù', + '溲' => ' sōu', + '溱' => ' qín', + '溰' => ' ái', + '溯' => ' sù', + '溮' => ' shī', + '溭' => ' zé', + '溬' => ' qiāng', + '溫' => ' wēn', + '溪' => ' xī', + '溩' => ' wù', + '溿' => ' pàn', + '滁' => ' chú', + '溧' => ' lì', + '滎' => ' xíng', + '滘' => ' jiào', + '滗' => ' bì', + '滖' => ' suī', + '滕' => ' téng', + '滔' => ' tāo', + '滓' => ' zǐ', + '滒' => ' gē', + '滑' => ' huá', + '滐' => ' jié', + '滏' => ' fǔ', + '滍' => ' zhì', + '滂' => ' pāng', + '滌' => ' dí', + '滋' => ' zī', + '滊' => ' xì', + '滉' => ' huàng', + '滈' => ' hào', + '滇' => ' diān', + '滆' => ' gé', + '滅' => ' miè', + '滄' => ' cāng', + '滃' => ' wēng', + '溨' => ' cái', + '溦' => ' wēi', + '湴' => ' bàn', + '満' => ' mǎn', + '溊' => ' xia', + '溉' => ' gài', + '溈' => ' wéi', + '溇' => ' lóu', + '溆' => ' xù', + '溅' => ' jiàn', + '溄' => ' feng', + '溃' => ' kuì', + '溂' => ' la', + '溁' => ' yíng', + '湿' => ' shī', + '溌' => ' pō', + '湾' => ' wān', + '湽' => ' zī', + '湼' => ' niè', + '湻' => ' chún', + '湺' => ' yán', + '湹' => ' chán', + '湸' => ' liàng', + '湷' => ' zhuāng', + '湶' => ' quán', + '湵' => ' yǒu', + '溋' => ' yíng', + '溍' => ' jìn', + '溥' => ' pǔ', + '溚' => ' tǎ', + '溤' => ' mǎ', + '溣' => ' lùn', + '溢' => ' yì', + '溡' => ' shí', + '溠' => ' zhà', + '溟' => ' míng', + '溞' => ' sāo', + '溝' => ' gōu', + '溜' => ' liū', + '溛' => ' wā', + '溙' => ' tài', + '溎' => ' yàn', + '溘' => ' kè', + '溗' => ' chéng', + '準' => ' zhǔn', + '溕' => ' mèng', + '溔' => ' yǎo', + '溓' => ' lián', + '溒' => ' yuán', + '溑' => ' suǒ', + '源' => ' yuán', + '溏' => ' táng', + '渌' => ' lù', + '渊' => ' yuān', + '活' => ' huó', + '浻' => ' jiǒng', + '涅' => ' niè', + '涄' => ' pīng', + '涃' => ' kùn', + '涂' => ' tú', + '涁' => ' shèn', + '涀' => ' xiàn', + '浿' => ' pèi', + '浾' => ' chēng', + '浽' => ' suī', + '浼' => ' měi', + '浺' => ' chōng', + '涇' => ' jīng', + '浹' => ' jiā', + '浸' => ' jìn', + '海' => ' hǎi', + '浶' => ' láo', + '浵' => ' tóng', + '浴' => ' yù', + '浳' => ' yì', + '浲' => ' féng', + '浱' => ' chún', + '浰' => ' liàn', + '涆' => ' hàn', + '消' => ' xiāo', + '浮' => ' fú', + '涕' => ' tì', + '涟' => ' lián', + '涞' => ' lái', + '涝' => ' lào', + '涜' => ' dú', + '涛' => ' tāo', + '涚' => ' shuì', + '涙' => ' lèi', + '涘' => ' sì', + '涗' => ' shuì', + '涖' => ' lì', + '涔' => ' cén', + '涉' => ' shè', + '涓' => ' juān', + '涒' => ' tūn', + '涑' => ' sù', + '涐' => ' é', + '涏' => ' tǐng', + '涎' => ' xián', + '涍' => ' xiào', + '涌' => ' yǒng', + '涋' => ' tū', + '涊' => ' niǎn', + '浯' => ' wú', + '浭' => ' gēng', + '涡' => ' wō', + '浇' => ' jiāo', + '浑' => ' hún', + '浐' => ' chǎn', + '浏' => ' liú', + '济' => ' jì', + '浍' => ' huì', + '浌' => ' fá', + '测' => ' cè', + '浊' => ' zhuó', + '浉' => ' shī', + '浈' => ' zhēn', + '浆' => ' jiāng', + '浓' => ' nóng', + '浅' => ' qiǎn', + '浄' => ' jìng', + '浃' => ' jiā', + '浂' => ' yì', + '流' => ' liú', + '浀' => ' qū', + '洿' => ' wū', + '派' => ' pài', + '洽' => ' qià', + '洼' => ' wā', + '浒' => ' hǔ', + '浔' => ' xún', + '浬' => ' lǐ', + '浡' => ' bó', + '浫' => ' hǎn', + '浪' => ' làng', + '浩' => ' hào', + '浨' => ' lǎn', + '浧' => ' yǐng', + '浦' => ' pǔ', + '浥' => ' yì', + '浤' => ' hóng', + '浣' => ' huàn', + '浢' => ' dòu', + '浠' => ' xī', + '浕' => ' jìn', + '浟' => ' yóu', + '浞' => ' zhuó', + '浝' => ' máng', + '浜' => ' bāng', + '浛' => ' hán', + '浚' => ' jùn', + '浙' => ' zhè', + '浘' => ' wěi', + '浗' => ' qiú', + '浖' => ' liè', + '涠' => ' wéi', + '涢' => ' yún', + '渉' => ' shè', + '淤' => ' yū', + '淮' => ' huái', + '淭' => ' qú', + '淬' => ' cuì', + '淫' => ' yín', + '淪' => ' lún', + '淩' => ' líng', + '淨' => ' jìng', + '淧' => ' mì', + '淦' => ' gàn', + '淥' => ' lù', + '淣' => ' ní', + '淰' => ' niǎn', + '淢' => ' yù', + '淡' => ' dàn', + '淠' => ' pì', + '淟' => ' tiǎn', + '淞' => ' sōng', + '淝' => ' féi', + '淜' => ' píng', + '淛' => ' zhè', + '淚' => ' lèi', + '淙' => ' cóng', + '淯' => ' yù', + '深' => ' shēn', + '淗' => ' jú', + '淾' => ' yǐn', + '済' => ' jì', + '渇' => ' kě', + '渆' => ' yuān', + '清' => ' qīng', + '渄' => ' fēi', + '渃' => ' ruò', + '渂' => ' wèn', + '渁' => ' yuān', + '渀' => ' bèn', + '淿' => ' mì', + '淽' => ' zhǐ', + '淲' => ' biāo', + '淼' => ' miǎo', + '添' => ' tiān', + '淺' => ' qiǎn', + '淹' => ' yān', + '淸' => ' qīng', + '混' => ' hùn', + '淶' => ' lái', + '淵' => ' yuān', + '淴' => ' hū', + '淳' => ' chún', + '淘' => ' táo', + '淖' => ' nào', + '涣' => ' huàn', + '涯' => ' yá', + '涹' => ' wō', + '涸' => ' hé', + '涷' => ' dōng', + '涶' => ' tuō', + '涵' => ' hán', + '涴' => ' wò', + '涳' => ' kōng', + '液' => ' yè', + '涱' => ' zhàng', + '涰' => ' chuò', + '涮' => ' shuàn', + '涻' => ' shè', + '涭' => ' shòu', + '涬' => ' xìng', + '涫' => ' guàn', + '涪' => ' fú', + '涩' => ' sè', + '涨' => ' zhǎng', + '涧' => ' jiàn', + '润' => ' rùn', + '涥' => ' heng', + '涤' => ' dí', + '涺' => ' jū', + '涼' => ' liáng', + '淕' => ' lù', + '淊' => ' yān', + '淔' => ' zhí', + '淓' => ' fāng', + '淒' => ' qī', + '淑' => ' shū', + '淐' => ' chāng', + '淏' => ' hào', + '淎' => ' pěng', + '淍' => ' zhōu', + '淌' => ' tǎng', + '淋' => ' lín', + '淉' => ' guǒ', + '涽' => ' hūn', + '淈' => ' gǔ', + '淇' => ' qí', + '淆' => ' xiáo', + '淅' => ' xī', + '淄' => ' zī', + '淃' => ' juàn', + '淂' => ' dé', + '淁' => ' qiè', + '淀' => ' diàn', + '涿' => ' zhuō', + '涾' => ' tà', + '爚' => ' yuè', + '爜' => ' cóng', + '碡' => ' dú', + '癳' => ' luǒ', + '白' => ' bái', + '發' => ' fā', + '登' => ' dēng', + '発' => ' fā', + '癹' => ' bá', + '癸' => ' guǐ', + '癷' => ' bō', + '癶' => ' bō', + '癵' => ' luán', + '癴' => ' luán', + '癲' => ' diān', + '癿' => ' qié', + '癱' => ' tān', + '癰' => ' yōng', + '癯' => ' qú', + '癮' => ' yǐn', + '癭' => ' yǐng', + '癬' => ' xuǎn', + '癫' => ' diān', + '癪' => ' jī', + '癩' => ' lài', + '癨' => ' huò', + '百' => ' bǎi', + '皀' => ' jí', + '癦' => ' me', + '皍' => ' jí', + '皗' => ' chóu', + '皖' => ' wǎn', + '皕' => ' bì', + '皔' => ' hàn', + '皓' => ' hào', + '皒' => ' é', + '皑' => ' ái', + '皐' => ' gāo', + '皏' => ' pěng', + '皎' => ' jiǎo', + '皌' => ' mò', + '皁' => ' zào', + '皋' => ' gāo', + '皊' => ' líng', + '皉' => ' cǐ', + '皈' => ' guī', + '皇' => ' huáng', + '皆' => ' jiē', + '皅' => ' pā', + '的' => ' de', + '皃' => ' mào', + '皂' => ' zào', + '癧' => ' lì', + '癥' => ' zhēng', + '皙' => ' xī', + '瘿' => ' yǐng', + '癉' => ' dān', + '癈' => ' fèi', + '癇' => ' xián', + '癆' => ' láo', + '癅' => ' liú', + '癄' => ' qiáo', + '癃' => ' lóng', + '療' => ' liáo', + '癁' => ' fú', + '癀' => ' huáng', + '瘾' => ' yǐn', + '癋' => ' hè', + '瘽' => ' qín', + '瘼' => ' mò', + '瘻' => ' lòu', + '瘺' => ' lòu', + '瘹' => ' diào', + '瘸' => ' qué', + '瘷' => ' sè', + '瘶' => ' sòu', + '瘵' => ' zhài', + '瘴' => ' zhàng', + '癊' => ' yìn', + '癌' => ' ái', + '癤' => ' jiē', + '癙' => ' shǔ', + '癣' => ' xuǎn', + '癢' => ' yǎng', + '癡' => ' chī', + '癠' => ' jì', + '癟' => ' biě', + '癞' => ' lài', + '癝' => ' lǐn', + '癜' => ' diàn', + '癛' => ' lǐn', + '癚' => ' dàn', + '癘' => ' lì', + '癍' => ' bān', + '癗' => ' lěi', + '癖' => ' pǐ', + '癕' => ' yōng', + '癔' => ' yì', + '癓' => ' wéi', + '癒' => ' yù', + '癑' => ' nòng', + '癐' => ' guì', + '癏' => ' guān', + '癎' => ' xián', + '皘' => ' qiàn', + '皚' => ' ái', + '瘲' => ' zòng', + '盛' => ' shèng', + '盥' => ' guàn', + '盤' => ' pán', + '監' => ' jiān', + '盢' => ' xù', + '盡' => ' jǐn', + '盠' => ' lí', + '盟' => ' méng', + '盞' => ' zhǎn', + '盝' => ' lù', + '盜' => ' dào', + '盚' => ' qiú', + '盧' => ' lú', + '盙' => ' fǔ', + '盘' => ' pán', + '盗' => ' dào', + '盖' => ' gài', + '盕' => ' fàn', + '盔' => ' kuī', + '盓' => ' yū', + '盒' => ' hé', + '监' => ' jiān', + '盐' => ' yán', + '盦' => ' ān', + '盨' => ' xǔ', + '盎' => ' àng', + '盵' => ' qì', + '盿' => ' mín', + '盾' => ' dùn', + '盽' => ' fēng', + '盼' => ' pàn', + '盻' => ' xì', + '盺' => ' xīn', + '盹' => ' dǔn', + '相' => ' xiāng', + '盷' => ' tián', + '盶' => ' yuǎn', + '直' => ' zhí', + '盩' => ' zhōu', + '盳' => ' wàng', + '盲' => ' máng', + '盱' => ' xū', + '盰' => ' gàn', + '盯' => ' dīng', + '目' => ' mù', + '盭' => ' lì', + '盬' => ' gǔ', + '盫' => ' ān', + '盪' => ' dàng', + '盏' => ' zhǎn', + '盍' => ' hé', + '皛' => ' xiǎo', + '皧' => ' ài', + '皱' => ' zhòu', + '皰' => ' pào', + '皯' => ' gǎn', + '皮' => ' pí', + '皭' => ' jiào', + '皬' => ' hé', + '皫' => ' piǎo', + '皪' => ' lì', + '皩' => ' huàng', + '皨' => ' xīng', + '皦' => ' jiǎo', + '皳' => ' qiú', + '皥' => ' hào', + '皤' => ' pó', + '䴹' => ' guǒ', + '皢' => ' xiǎo', + '皡' => ' hào', + '皠' => ' cuǐ', + '皟' => ' zé', + '皞' => ' hào', + '皝' => ' huàng', + '皜' => ' hào', + '皲' => ' jūn', + '皴' => ' cūn', + '盌' => ' wǎn', + '盁' => ' yíng', + '盋' => ' bō', + '益' => ' yì', + '盉' => ' hé', + '盈' => ' yíng', + '盇' => ' hé', + '盆' => ' pén', + '盅' => ' zhōng', + '盄' => ' zhāo', + '盃' => ' bēi', + '盂' => ' yú', + '盀' => ' qǐ', + '皵' => ' què', + '皿' => ' mǐn', + '皾' => ' dú', + '皽' => ' zhāo', + '皼' => ' gǔ', + '皻' => ' zhā', + '皺' => ' zhòu', + '皹' => ' jūn', + '皸' => ' jūn', + '皷' => ' gǔ', + '皶' => ' zhā', + '瘳' => ' chōu', + '瘱' => ' yì', + '省' => ' shěng', + '疣' => ' yóu', + '疭' => ' zòng', + '疬' => ' lì', + '疫' => ' yì', + '疪' => ' bì', + '疩' => ' cuì', + '疨' => ' xiā', + '疧' => ' qí', + '疦' => ' jué', + '疥' => ' jiè', + '疤' => ' bā', + '疢' => ' chèn', + '疯' => ' fēng', + '疡' => ' yáng', + '疠' => ' lì', + '疟' => ' nüè', + '疞' => ' xū', + '疝' => ' shàn', + '疜' => ' xià', + '疛' => ' zhǒu', + '疚' => ' jiù', + '疙' => ' gē', + '疘' => ' gāng', + '疮' => ' chuāng', + '疰' => ' zhù', + '疖' => ' jiē', + '疽' => ' jū', + '症' => ' zhèng', + '痆' => ' niè', + '病' => ' bìng', + '痄' => ' zhà', + '痃' => ' xuán', + '痂' => ' jiā', + '痁' => ' shān', + '痀' => ' jū', + '疿' => ' fèi', + '疾' => ' jí', + '疼' => ' téng', + '疱' => ' pào', + '疻' => ' zhǐ', + '疺' => ' fá', + '疹' => ' zhěn', + '疸' => ' dǎn', + '疷' => ' zhī', + '疶' => ' xuē', + '疵' => ' cī', + '疴' => ' kē', + '疳' => ' gān', + '疲' => ' pí', + '疗' => ' liáo', + '疕' => ' bǐ', + '痉' => ' jìng', + '畯' => ' jùn', + '畹' => ' wǎn', + '畸' => ' jī', + '畷' => ' zhuì', + '當' => ' dāng', + '畵' => ' huà', + '畴' => ' chóu', + '畳' => ' dié', + '畲' => ' shē', + '畱' => ' liú', + '異' => ' yì', + '畮' => ' mǔ', + '畻' => ' chéng', + '畭' => ' yú', + '畬' => ' shē', + '畫' => ' huà', + '番' => ' fān', + '畩' => ' yi', + '畨' => ' pān', + '畧' => ' lüè', + '畦' => ' qí', + '略' => ' lüè', + '畤' => ' zhì', + '畺' => ' jiāng', + '畼' => ' chàng', + '疔' => ' dīng', + '疉' => ' dié', + '疓' => ' nǎi', + '疒' => ' nè', + '疑' => ' yí', + '疐' => ' zhì', + '疏' => ' shū', + '疎' => ' shū', + '疍' => ' dàn', + '疌' => ' jié', + '疋' => ' pǐ', + '疊' => ' dié', + '疈' => ' pì', + '畽' => ' tǔn', + '疇' => ' chóu', + '疆' => ' jiāng', + '疅' => ' jiāng', + '疄' => ' lìn', + '疃' => ' tuǎn', + '疂' => ' die', + '疁' => ' liú', + '疀' => ' chā', + '畿' => ' jī', + '畾' => ' léi', + '痈' => ' yōng', + '痊' => ' quán', + '瘰' => ' luǒ', + '瘋' => ' fēng', + '瘕' => ' jiǎ', + '瘔' => ' kù', + '瘓' => ' huàn', + '瘒' => ' wén', + '瘑' => ' guō', + '瘐' => ' yǔ', + '瘏' => ' tú', + '瘎' => ' chén', + '瘍' => ' yáng', + '瘌' => ' là', + '瘊' => ' hóu', + '瘗' => ' yì', + '瘉' => ' yù', + '瘈' => ' chì', + '瘇' => ' zhǒng', + '瘆' => ' shèn', + '瘅' => ' dān', + '瘄' => ' cù', + '瘃' => ' zhú', + '瘂' => ' yǎ', + '瘁' => ' cuì', + '瘀' => ' yū', + '瘖' => ' yīn', + '瘘' => ' lòu', + '痾' => ' ē', + '瘥' => ' chài', + '瘯' => ' cù', + '瘮' => ' shèn', + '瘭' => ' biāo', + '瘬' => ' zhàng', + '瘫' => ' tān', + '瘪' => ' biě', + '瘩' => ' da', + '瘨' => ' diān', + '瘧' => ' nüè', + '瘦' => ' shòu', + '瘤' => ' liú', + '瘙' => ' sào', + '瘣' => ' huì', + '瘢' => ' bān', + '瘡' => ' chuāng', + '瘠' => ' jí', + '瘟' => ' wēn', + '瘞' => ' yì', + '瘝' => ' guān', + '瘜' => ' xī', + '瘛' => ' chì', + '瘚' => ' jué', + '痿' => ' wěi', + '痽' => ' duī', + '痋' => ' téng', + '痗' => ' mèi', + '痡' => ' fū', + '痠' => ' suān', + '痟' => ' xiāo', + '痞' => ' pǐ', + '痝' => ' máng', + '痜' => ' tū', + '痛' => ' tòng', + '痚' => ' xiāo', + '痙' => ' jìng', + '痘' => ' dòu', + '痖' => ' yǎ', + '痣' => ' zhì', + '痕' => ' hén', + '痔' => ' zhì', + '痓' => ' chì', + '痒' => ' yǎng', + '痑' => ' tān', + '痐' => ' huí', + '痏' => ' wěi', + '痎' => ' jiē', + '痍' => ' yí', + '痌' => ' tōng', + '痢' => ' lì', + '痤' => ' cuó', + '痼' => ' gù', + '痱' => ' fèi', + '痻' => ' mín', + '痺' => ' bì', + '痹' => ' bì', + '痸' => ' chì', + '痷' => ' ān', + '痶' => ' tiǎn', + '痵' => ' jì', + '痴' => ' chī', + '痳' => ' lín', + '痲' => ' má', + '痰' => ' tán', + '痥' => ' duó', + '痯' => ' guǎn', + '痮' => ' zhàng', + '痭' => ' bēng', + '痬' => ' yì', + '痫' => ' xián', + '痪' => ' huàn', + '痩' => ' shòu', + '痨' => ' láo', + '痧' => ' shā', + '痦' => ' wù', + '眀' => ' míng', + '眂' => ' shì', + '畢' => ' bì', + '研' => ' yán', + '砞' => ' mò', + '砝' => ' fá', + '砜' => ' fēng', + '砛' => ' jin', + '砚' => ' yàn', + '砙' => ' pān', + '砘' => ' dùn', + '砗' => ' chē', + '砖' => ' zhuān', + '砕' => ' suì', + '砓' => ' zhé', + '砠' => ' jū', + '砒' => ' pī', + '砑' => ' yà', + '砐' => ' è', + '砏' => ' bīn', + '砎' => ' jiè', + '砍' => ' kǎn', + '砌' => ' qì', + '砋' => ' zhǐ', + '砊' => ' kāng', + '砉' => ' huò', + '砟' => ' zhǎ', + '砡' => ' yù', + '砇' => ' mín', + '砮' => ' nǔ', + '砸' => ' zá', + '砷' => ' shēn', + '砶' => ' pò', + '砵' => ' bō', + '破' => ' pò', + '砳' => ' lè', + '砲' => ' pào', + '砱' => ' líng', + '砰' => ' pēng', + '砯' => ' pīng', + '砭' => ' biān', + '砢' => ' kē', + '砬' => ' lá', + '砫' => ' zhù', + '砪' => ' mǔ', + '砩' => ' fú', + '砨' => ' è', + '砧' => ' zhēn', + '砦' => ' zhài', + '砥' => ' dǐ', + '砤' => ' tuó', + '砣' => ' tuó', + '砈' => ' ě', + '砆' => ' fū', + '砺' => ' lì', + '矠' => ' zé', + '矪' => ' zhōu', + '矩' => ' jǔ', + '矨' => ' yǐng', + '矧' => ' shěn', + '矦' => ' hóu', + '知' => ' zhī', + '矤' => ' shěn', + '矣' => ' yǐ', + '矢' => ' shǐ', + '矡' => ' jué', + '矟' => ' shuò', + '矬' => ' cuó', + '矞' => ' yù', + '矝' => ' lín', + '矜' => ' jīn', + '矛' => ' máo', + '矚' => ' zhǔ', + '矙' => ' kàn', + '矘' => ' tǎng', + '矗' => ' chù', + '矖' => ' xǐ', + '矕' => ' mǎn', + '矫' => ' jiǎo', + '短' => ' duǎn', + '砅' => ' lì', + '矺' => ' zhé', + '砄' => ' jué', + '砃' => ' dān', + '砂' => ' shā', + '码' => ' mǎ', + '砀' => ' dàng', + '矿' => ' kuàng', + '矾' => ' fán', + '矽' => ' xì', + '矼' => ' gāng', + '矻' => ' kū', + '矹' => ' wù', + '矮' => ' ǎi', + '矸' => ' gān', + '矷' => ' zǐ', + '矶' => ' jī', + '矵' => ' qì', + '矴' => ' dìng', + '石' => ' shí', + '矲' => ' bà', + '矱' => ' yuē', + '矰' => ' zēng', + '矯' => ' jiǎo', + '砹' => ' ài', + '砻' => ' lóng', + '矓' => ' lóng', + '硼' => ' péng', + '碆' => ' bō', + '碅' => ' jūn', + '碄' => ' lín', + '碃' => ' qìng', + '碂' => ' zòng', + '碁' => ' qí', + '碀' => ' chéng', + '硿' => ' kōng', + '硾' => ' zhuì', + '硽' => ' yān', + '硻' => ' kēng', + '碈' => ' mín', + '硺' => ' zhuó', + '硹' => ' sōng', + '硸' => ' nüè', + '硷' => ' jiǎn', + '硶' => ' chěn', + '硵' => ' lǔ', + '硴' => ' hua', + '硳' => ' chì', + '硲' => ' yù', + '硱' => ' kǔn', + '碇' => ' dìng', + '碉' => ' diāo', + '硯' => ' yàn', + '碖' => ' lǔn', + '碠' => ' dìng', + '碟' => ' dié', + '碞' => ' yán', + '碝' => ' ruǎn', + '碜' => ' chěn', + '碛' => ' qì', + '碚' => ' bèi', + '碙' => ' náo', + '碘' => ' diǎn', + '碗' => ' wǎn', + '碕' => ' qí', + '碊' => ' jiān', + '碔' => ' wǔ', + '碓' => ' duì', + '碒' => ' yín', + '碑' => ' bēi', + '碐' => ' léng', + '碏' => ' què', + '碎' => ' suì', + '碍' => ' ài', + '碌' => ' lù', + '碋' => ' hè', + '硰' => ' shā', + '确' => ' què', + '砼' => ' tóng', + '硈' => ' qià', + '硒' => ' xī', + '硑' => ' pēng', + '硐' => ' dòng', + '硏' => ' yán', + '硎' => ' xíng', + '硍' => ' xiàn', + '硌' => ' gè', + '硋' => ' ài', + '硊' => ' wěi', + '硉' => ' lù', + '硇' => ' náo', + '硔' => ' hóng', + '硆' => ' è', + '硅' => ' guī', + '硄' => ' kuāng', + '硃' => ' zhū', + '硂' => ' quán', + '硁' => ' kēng', + '础' => ' chǔ', + '砿' => ' kuang', + '砾' => ' lì', + '砽' => ' yong', + '硓' => ' lao', + '硕' => ' shuò', + '硭' => ' máng', + '硢' => ' yú', + '硬' => ' yìng', + '硫' => ' liú', + '硪' => ' wò', + '硩' => ' chè', + '硨' => ' chē', + '硧' => ' yǒng', + '硦' => ' luò', + '硥' => ' mǎng', + '硤' => ' xiá', + '硣' => ' xiāo', + '硡' => ' hōng', + '硖' => ' xiá', + '硠' => ' láng', + '硟' => ' chàn', + '硞' => ' què', + '硝' => ' xiāo', + '硜' => ' kēng', + '硛' => ' yì', + '硚' => ' qiáo', + '硙' => ' wéi', + '硘' => ' qing', + '硗' => ' qiāo', + '矔' => ' guàn', + '矒' => ' méng', + '眃' => ' yún', + '睃' => ' suō', + '睍' => ' xiàn', + '睌' => ' mǎn', + '睋' => ' é', + '睊' => ' juàn', + '睉' => ' cuó', + '睈' => ' chěng', + '睇' => ' dì', + '睆' => ' huàn', + '睅' => ' hàn', + '睄' => ' shào', + '睂' => ' méi', + '睏' => ' kùn', + '睁' => ' zhēng', + '着' => ' zhe', + '眿' => ' mò', + '眾' => ' zhòng', + '眽' => ' mò', + '眼' => ' yǎn', + '眻' => ' yáng', + '眺' => ' tiào', + '眹' => ' zhèn', + '眸' => ' móu', + '睎' => ' xī', + '睐' => ' lài', + '眶' => ' kuàng', + '睝' => ' lí', + '睧' => ' hūn', + '睦' => ' mù', + '睥' => ' pì', + '睤' => ' bì', + '督' => ' dū', + '睢' => ' suī', + '睡' => ' shuì', + '睠' => ' juàn', + '睟' => ' suì', + '睞' => ' lài', + '睜' => ' zhēng', + '睑' => ' jiǎn', + '睛' => ' jīng', + '睚' => ' yá', + '睙' => ' liè', + '睘' => ' qióng', + '睗' => ' shì', + '睖' => ' lèng', + '睕' => ' wǎn', + '睔' => ' gùn', + '睓' => ' tiǎn', + '睒' => ' shǎn', + '眷' => ' juàn', + '眵' => ' chī', + '睩' => ' lù', + '眏' => ' yāng', + '眙' => ' yí', + '眘' => ' shèn', + '眗' => ' jū', + '眖' => ' kuàng', + '眕' => ' zhěn', + '眔' => ' dà', + '眓' => ' huò', + '眒' => ' shēn', + '眑' => ' yǎo', + '眐' => ' zhēng', + '眎' => ' shì', + '眛' => ' mèi', + '眍' => ' kōu', + '県' => ' xiàn', + '看' => ' kàn', + '眊' => ' mào', + '眉' => ' méi', + '眈' => ' dān', + '眇' => ' miǎo', + '眆' => ' fǎng', + '眅' => ' pān', + '眄' => ' miǎn', + '眚' => ' shěng', + '眜' => ' mò', + '眴' => ' xuàn', + '眩' => ' xuàn', + '眳' => ' míng', + '眲' => ' nè', + '眱' => ' dì', + '眰' => ' diè', + '眯' => ' mī', + '眮' => ' tóng', + '眭' => ' suī', + '眬' => ' lóng', + '眫' => ' mǐ', + '眪' => ' bǐng', + '眨' => ' zhǎ', + '眝' => ' zhù', + '眧' => ' chǎo', + '眦' => ' zì', + '眥' => ' zì', + '眤' => ' nì', + '眣' => ' dié', + '眢' => ' yuān', + '眡' => ' shì', + '眠' => ' mián', + '真' => ' zhēn', + '眞' => ' zhēn', + '睨' => ' nì', + '睪' => ' yì', + '矑' => ' lú', + '瞬' => ' shùn', + '瞶' => ' guì', + '瞵' => ' lín', + '瞴' => ' móu', + '瞳' => ' tóng', + '瞲' => ' xù', + '瞱' => ' yè', + '瞰' => ' kàn', + '瞯' => ' xián', + '瞮' => ' chè', + '瞭' => ' liǎo', + '瞫' => ' shěn', + '瞸' => ' yè', + '瞪' => ' dèng', + '瞩' => ' zhǔ', + '瞨' => ' pú', + '瞧' => ' qiáo', + '瞦' => ' xī', + '瞥' => ' piē', + '瞤' => ' rún', + '瞣' => ' huan', + '瞢' => ' méng', + '瞡' => ' guǐ', + '瞷' => ' jiàn', + '瞹' => ' ài', + '瞟' => ' piǎo', + '矆' => ' huò', + '矐' => ' huò', + '矏' => ' mián', + '矎' => ' xuān', + '矍' => ' jué', + '矌' => ' kuàng', + '矋' => ' lì', + '矊' => ' mián', + '矉' => ' pín', + '矈' => ' mián', + '矇' => ' méng', + '矅' => ' yào', + '瞺' => ' huì', + '矄' => ' xūn', + '矃' => ' nǐng', + '矂' => ' sào', + '矁' => ' chǒu', + '矀' => ' méi', + '瞿' => ' qú', + '瞾' => ' zhào', + '瞽' => ' gǔ', + '瞼' => ' jiǎn', + '瞻' => ' zhān', + '瞠' => ' chēng', + '瞞' => ' mán', + '睫' => ' jié', + '睷' => ' jiān', + '瞁' => ' xù', + '瞀' => ' mào', + '睿' => ' ruì', + '睾' => ' gāo', + '睽' => ' kuí', + '睼' => ' tiàn', + '睻' => ' xuān', + '睺' => ' hóu', + '睹' => ' dǔ', + '睸' => ' mèi', + '睶' => ' chǔn', + '瞃' => ' wò', + '睵' => ' zāi', + '睴' => ' gùn', + '睳' => ' huī', + '睲' => ' xǐng', + '睱' => ' xià', + '睰' => ' mà', + '睯' => ' hūn', + '睮' => ' yú', + '睭' => ' zhǒu', + '睬' => ' cǎi', + '瞂' => ' fá', + '瞄' => ' miáo', + '瞝' => ' chī', + '瞒' => ' mán', + '瞜' => ' lōu', + '瞛' => ' cōng', + '瞚' => ' shùn', + '瞙' => ' mò', + '瞘' => ' kōu', + '瞗' => ' diāo', + '瞖' => ' yì', + '瞕' => ' zhàng', + '瞔' => ' zé', + '瞓' => ' shuì', + '瞑' => ' míng', + '瞅' => ' chǒu', + '瞐' => ' mò', + '瞏' => ' qióng', + '瞎' => ' xiā', + '瞍' => ' sǒu', + '瞌' => ' kē', + '瞋' => ' chēn', + '瞊' => ' dàng', + '瞉' => ' kòu', + '瞈' => ' wěng', + '瞇' => ' mī', + '瞆' => ' kuì', + '畣' => ' dá', + '畡' => ' gāi', + '爝' => ' jué', + '猭' => ' chuān', + '猷' => ' yóu', + '猶' => ' yóu', + '猵' => ' biān', + '猴' => ' hóu', + '猳' => ' jiā', + '猲' => ' xiē', + '猱' => ' náo', + '猰' => ' yà', + '猯' => ' tuān', + '献' => ' xiàn', + '猬' => ' wèi', + '猹' => ' chá', + '猫' => ' māo', + '猪' => ' zhū', + '猩' => ' xīng', + '猨' => ' yuán', + '猧' => ' wō', + '猦' => ' fēng', + '猥' => ' wěi', + '猤' => ' guì', + '猣' => ' zōng', + '猢' => ' hú', + '猸' => ' méi', + '猺' => ' yáo', + '猠' => ' diǎn', + '獇' => ' qiang', + '獑' => ' chán', + '獐' => ' zhāng', + '獏' => ' mò', + '獎' => ' jiǎng', + '獍' => ' jìng', + '獌' => ' màn', + '獋' => ' háo', + '獊' => ' cāng', + '獉' => ' zhēn', + '獈' => ' yì', + '獆' => ' háo', + '猻' => ' sūn', + '獅' => ' shī', + '獄' => ' yù', + '獃' => ' dāi', + '獂' => ' yuán', + '獁' => ' mà', + '獀' => ' sōu', + '猿' => ' yuán', + '猾' => ' huá', + '猽' => ' míng', + '猼' => ' bó', + '猡' => ' luó', + '猟' => ' lie', + '獓' => ' áo', + '狹' => ' xiá', + '猃' => ' xiǎn', + '猂' => ' hàn', + '猁' => ' lì', + '猀' => ' shā', + '狿' => ' yán', + '狾' => ' zhì', + '狽' => ' bèi', + '狼' => ' láng', + '狻' => ' suān', + '狺' => ' yín', + '狸' => ' lí', + '猅' => ' pái', + '狷' => ' juàn', + '狶' => ' xī', + '狵' => ' máng', + '狴' => ' bì', + '狳' => ' yú', + '狲' => ' sūn', + '狱' => ' yù', + '狰' => ' zhēng', + '狯' => ' kuài', + '狮' => ' shī', + '猄' => ' jīng', + '猆' => ' fēi', + '猞' => ' shē', + '猓' => ' guǒ', + '猝' => ' cù', + '猜' => ' cāi', + '猛' => ' měng', + '猚' => ' yá', + '猙' => ' zhēng', + '猘' => ' zhì', + '猗' => ' yī', + '猖' => ' chāng', + '猕' => ' mí', + '猔' => ' zòng', + '猒' => ' yān', + '猇' => ' xiāo', + '猑' => ' kūn', + '猐' => ' qiāng', + '猏' => ' jiān', + '猎' => ' liè', + '猍' => ' lái', + '猌' => ' yìn', + '猋' => ' biāo', + '猊' => ' ní', + '猉' => ' qí', + '猈' => ' bài', + '獒' => ' áo', + '獔' => ' háo', + '独' => ' dú', + '玕' => ' gān', + '玟' => ' wén', + '玞' => ' fū', + '玝' => ' wǔ', + '玜' => ' gōng', + '玛' => ' mǎ', + '玚' => ' chàng', + '玙' => ' yú', + '玘' => ' qǐ', + '玗' => ' yú', + '玖' => ' jiǔ', + '玔' => ' chuàn', + '玡' => ' yá', + '玓' => ' dì', + '玒' => ' hóng', + '玑' => ' jī', + '玐' => ' bā', + '玏' => ' lè', + '玎' => ' dīng', + '玍' => ' gǎ', + '玌' => ' qiú', + '王' => ' wáng', + '玊' => ' sù', + '玠' => ' jiè', + '玢' => ' bīn', + '玈' => ' lú', + '环' => ' huán', + '玹' => ' xuán', + '玸' => ' fú', + '玷' => ' diàn', + '玶' => ' píng', + '玵' => ' án', + '玴' => ' yì', + '玳' => ' dài', + '玲' => ' líng', + '玱' => ' qiāng', + '现' => ' xiàn', + '玮' => ' wěi', + '玣' => ' biàn', + '玭' => ' pín', + '玬' => ' dǎn', + '玫' => ' méi', + '玪' => ' jiān', + '玩' => ' wán', + '玨' => ' jué', + '玧' => ' mén', + '玦' => ' jué', + '玥' => ' yuè', + '玤' => ' bàng', + '玉' => ' yù', + '率' => ' lǜ', + '獕' => ' cuī', + '獡' => ' shuò', + '獫' => ' xiǎn', + '獪' => ' kuài', + '獩' => ' huì', + '獨' => ' dú', + '獧' => ' juàn', + '獦' => ' gé', + '獥' => ' jiào', + '獤' => ' dūn', + '獣' => ' shou', + '獢' => ' xiāo', + '獠' => ' liáo', + '獭' => ' tǎ', + '獟' => ' yào', + '獞' => ' tóng', + '獝' => ' xù', + '獜' => ' lín', + '獛' => ' pú', + '獚' => ' huáng', + '獙' => ' bì', + '獘' => ' bì', + '獗' => ' jué', + '獖' => ' bèn', + '獬' => ' xiè', + '獮' => ' xiǎn', + '玆' => ' zī', + '獻' => ' xiàn', + '玅' => ' miào', + '玄' => ' xuán', + '玃' => ' jué', + '玂' => ' qí', + '玁' => ' xiǎn', + '玀' => ' luó', + '獿' => ' nǎo', + '獾' => ' huān', + '獽' => ' ráng', + '獼' => ' mí', + '獺' => ' tǎ', + '獯' => ' xūn', + '獹' => ' lú', + '獸' => ' shòu', + '獷' => ' guǎng', + '獶' => ' nǎo', + '獵' => ' liè', + '獴' => ' měng', + '獳' => ' nòu', + '獲' => ' huò', + '獱' => ' pín', + '獰' => ' níng', + '狭' => ' xiá', + '狫' => ' lǎo', + '玻' => ' bō', + '牝' => ' pìn', + '牧' => ' mù', + '牦' => ' máo', + '牥' => ' fāng', + '牤' => ' māng', + '牣' => ' rèn', + '牢' => ' láo', + '薣' => ' gǔ', + '牠' => ' tā', + '牟' => ' móu', + '牞' => ' jiū', + '牜' => ' niu', + '物' => ' wù', + '牛' => ' niú', + '牚' => ' chēng', + '牙' => ' yá', + '牘' => ' dú', + '牗' => ' you', + '牖' => ' yǒu', + '牕' => ' chuāng', + '牔' => ' bó', + '牓' => ' bǎng', + '牒' => ' dié', + '牨' => ' gāng', + '牪' => ' yàn', + '牐' => ' zhá', + '牷' => ' quán', + '犁' => ' lí', + '犀' => ' xī', + '牿' => ' gù', + '牾' => ' wǔ', + '牽' => ' qiān', + '牼' => ' kēng', + '牻' => ' máng', + '牺' => ' xī', + '特' => ' tè', + '牸' => ' zì', + '牶' => ' quàn', + '牫' => ' gē', + '牵' => ' qiān', + '牴' => ' dǐ', + '牳' => ' mǔ', + '牲' => ' shēng', + '牱' => ' gē', + '牰' => ' yòu', + '牯' => ' gǔ', + '牮' => ' jiàn', + '牭' => ' sì', + '牬' => ' bèi', + '牑' => ' biān', + '牏' => ' yú', + '犃' => ' pǒu', + '爩' => ' yù', + '爳' => ' han', + '爲' => ' wèi', + '爱' => ' ài', + '爰' => ' yuán', + '爯' => ' chēng', + '爮' => ' páo', + '爭' => ' zhēng', + '爬' => ' pá', + '爫' => ' zhao', + '爪' => ' zhǎo', + '爨' => ' cuàn', + '爵' => ' jué', + '爧' => ' líng', + '爦' => ' lǎn', + '爥' => ' zhú', + '爤' => ' làn', + '爣' => ' tǎng', + '爢' => ' mí', + '爡' => ' chè', + '爠' => ' ju', + '爟' => ' guàn', + '爞' => ' chóng', + '爴' => ' jué', + '父' => ' fù', + '牎' => ' chuāng', + '牃' => ' dié', + '牍' => ' dú', + '牌' => ' pái', + '牋' => ' jiān', + '牊' => ' cháo', + '牉' => ' pàn', + '版' => ' bǎn', + '片' => ' piàn', + '牆' => ' qiáng', + '牅' => ' yóng', + '牄' => ' qiāng', + '牂' => ' zāng', + '爷' => ' yé', + '牁' => ' kē', + '牀' => ' chuáng', + '爿' => ' pán', + '爾' => ' ěr', + '爽' => ' shuǎng', + '爼' => ' zǔ', + '爻' => ' yáo', + '爺' => ' yé', + '爹' => ' diē', + '爸' => ' bà', + '犂' => ' lí', + '犄' => ' jī', + '狪' => ' tóng', + '狅' => ' qīng', + '狏' => ' tuó', + '狎' => ' xiá', + '狍' => ' páo', + '狌' => ' shēng', + '狋' => ' yí', + '狊' => ' jú', + '狉' => ' pī', + '狈' => ' bèi', + '狇' => ' mù', + '狆' => ' zhòng', + '狄' => ' dí', + '狑' => ' líng', + '狃' => ' niǔ', + '狂' => ' kuáng', + '狁' => ' yǔn', + '狀' => ' zhuàng', + '犿' => ' huān', + '犾' => ' yín', + '犽' => ' yà', + '犼' => ' hǒu', + '犻' => ' bó', + '犺' => ' kàng', + '狐' => ' hú', + '狒' => ' fèi', + '犸' => ' mà', + '狟' => ' huán', + '狩' => ' shòu', + '狨' => ' róng', + '狧' => ' tà', + '狦' => ' shān', + '狥' => ' xùn', + '狤' => ' jí', + '狣' => ' zhào', + '狢' => ' hé', + '狡' => ' jiǎo', + '狠' => ' hěn', + '狞' => ' níng', + '狓' => ' pí', + '狝' => ' xiǎn', + '狜' => ' kǔ', + '狛' => ' bó', + '狚' => ' dàn', + '狙' => ' jū', + '狘' => ' xuè', + '狗' => ' gǒu', + '狖' => ' yòu', + '狕' => ' yǎo', + '狔' => ' nǐ', + '犹' => ' yóu', + '犷' => ' guǎng', + '犅' => ' gāng', + '犑' => ' jú', + '犛' => ' máo', + '犚' => ' wèi', + '犙' => ' sān', + '犘' => ' má', + '犗' => ' jiè', + '犖' => ' luò', + '犕' => ' bèi', + '犔' => ' xì', + '犓' => ' chú', + '犒' => ' kào', + '犐' => ' kē', + '犝' => ' tóng', + '犏' => ' piān', + '犎' => ' fēng', + '犍' => ' jiān', + '犌' => ' jiā', + '犋' => ' jù', + '犊' => ' dú', + '犉' => ' chún', + '犈' => ' quán', + '犇' => ' bēn', + '犆' => ' zhí', + '犜' => ' dūn', + '犞' => ' qiao', + '状' => ' zhuàng', + '犫' => ' chōu', + '犵' => ' gē', + '犴' => ' àn', + '犳' => ' zhuó', + '犲' => ' cái', + '犱' => ' jǐ', + '犰' => ' qiú', + '犯' => ' fàn', + '犮' => ' bá', + '犭' => ' quǎn', + '犬' => ' quǎn', + '犪' => ' kuí', + '犟' => ' jiàng', + '犩' => ' wéi', + '犨' => ' chōu', + '犧' => ' xī', + '犦' => ' bó', + '犥' => ' piāo', + '犤' => ' pái', + '犣' => ' liè', + '犢' => ' dú', + '犡' => ' lì', + '犠' => ' xi', + '玺' => ' xǐ', + '玼' => ' cǐ', + '畠' => ' tián', + '瓎' => ' là', + '瓘' => ' guàn', + '瓗' => ' qióng', + '瓖' => ' xiāng', + '瓕' => ' mí', + '瓔' => ' yīng', + '瓓' => ' làn', + '瓒' => ' zàn', + '瓑' => ' lì', + '瓐' => ' lú', + '瓏' => ' lóng', + '瓍' => ' suí', + '瓚' => ' zàn', + '瓌' => ' guī', + '瓋' => ' tì', + '瓊' => ' qióng', + '瓉' => ' zàn', + '瓈' => ' lí', + '瓇' => ' róu', + '瓆' => ' zhì', + '瓅' => ' lì', + '瓄' => ' dú', + '瓃' => ' léi', + '瓙' => ' dào', + '瓛' => ' huán', + '瓁' => ' wò', + '瓩' => ' qiān', + '瓵' => ' yí', + '瓴' => ' líng', + '瓳' => ' hú', + '瓲' => ' wa', + '瓯' => ' ōu', + '瓮' => ' wèng', + '瓭' => ' dǎn', + '瓬' => ' fǎng', + '瓫' => ' pén', + '瓪' => ' bǎn', + '瓨' => ' xiáng', + '瓜' => ' guā', + '瓦' => ' wǎ', + '瓥' => ' lì', + '瓤' => ' ráng', + '瓣' => ' bàn', + '瓢' => ' piáo', + '瓡' => ' zhí', + '瓠' => ' hù', + '瓟' => ' bó', + '瓞' => ' dié', + '瓝' => ' bó', + '瓂' => ' gài', + '瓀' => ' ruǎn', + '瓷' => ' cí', + '璚' => ' qióng', + '璤' => ' hui', + '璣' => ' jī', + '璢' => ' liú', + '璡' => ' jìn', + '璠' => ' fán', + '璟' => ' jǐng', + '璞' => ' pú', + '璝' => ' guī', + '璜' => ' huáng', + '璛' => ' sù', + '璙' => ' liáo', + '璦' => ' ài', + '璘' => ' lín', + '璗' => ' dàng', + '璖' => ' qú', + '璕' => ' xún', + '璔' => ' zēng', + '璓' => ' xiù', + '璒' => ' dēng', + '璑' => ' wú', + '璐' => ' lù', + '璏' => ' wèi', + '璥' => ' jǐng', + '璧' => ' bì', + '璿' => ' xuán', + '璴' => ' chu', + '璾' => ' zī', + '璽' => ' xǐ', + '璼' => ' lán', + '璻' => ' zuǐ', + '璺' => ' wèn', + '璹' => ' shú', + '璸' => ' bīn', + '璷' => ' lú', + '璶' => ' jìn', + '璵' => ' yú', + '璳' => ' tián', + '璨' => ' càn', + '璲' => ' suì', + '璱' => ' sè', + '環' => ' huán', + '璯' => ' huì', + '璮' => ' tǎn', + '璭' => ' gùn', + '璬' => ' jiǎo', + '璫' => ' dāng', + '璪' => ' zǎo', + '璩' => ' qú', + '瓶' => ' píng', + '瓸' => ' bǎi', + '璍' => ' hua', + '画' => ' huà', + '畅' => ' chàng', + '畄' => ' liú', + '畃' => ' xún', + '畂' => ' liù', + '畁' => ' qí', + '畀' => ' bì', + '甿' => ' méng', + '甾' => ' zāi', + '甽' => ' zhèn', + '甼' => ' tǐng', + '町' => ' tīng', + '畇' => ' yún', + '甹' => ' pīng', + '甸' => ' diān', + '男' => ' nán', + '甶' => ' fú', + '电' => ' diàn', + '甴' => ' zhá', + '申' => ' shēn', + '甲' => ' jiǎ', + '由' => ' yóu', + '田' => ' tián', + '畆' => ' mǔ', + '畈' => ' fàn', + '甮' => ' fèng', + '畕' => ' jiāng', + '畟' => ' cè', + '畞' => ' mǔ', + '畝' => ' mǔ', + '畜' => ' chù', + '畛' => ' zhěn', + '畚' => ' běn', + '留' => ' liú', + '畘' => ' nán', + '畗' => ' dá', + '畖' => ' wā', + '畔' => ' pàn', + '畉' => ' fú', + '畓' => ' duō', + '畒' => ' mǔ', + '畑' => ' tián', + '畐' => ' fú', + '畏' => ' wèi', + '畎' => ' quǎn', + '畍' => ' jiè', + '界' => ' jiè', + '畋' => ' tián', + '畊' => ' gēng', + '甯' => ' níng', + '甭' => ' béng', + '瓹' => ' juān', + '甇' => ' yīng', + '甑' => ' zèng', + '甐' => ' lìn', + '甏' => ' bèng', + '甎' => ' zhuān', + '甍' => ' méng', + '甌' => ' ōu', + '甋' => ' dì', + '甊' => ' lǒu', + '甉' => ' xián', + '甈' => ' qì', + '甆' => ' cí', + '甓' => ' pì', + '甄' => ' zhēn', + '甃' => ' zhòu', + '甂' => ' biān', + '甁' => ' píng', + '甀' => ' zhuì', + '瓿' => ' bù', + '瓾' => ' měng', + '瓽' => ' dàng', + '瓻' => ' chī', + '瓺' => ' cháng', + '甒' => ' wǔ', + '甔' => ' dān', + '甬' => ' yǒng', + '甡' => ' shēn', + '甫' => ' fǔ', + '甪' => ' lù', + '甩' => ' shuǎi', + '用' => ' yòng', + '甧' => ' shēn', + '甦' => ' sū', + '甥' => ' shēng', + '甤' => ' ruí', + '産' => ' chǎn', + '產' => ' chǎn', + '甠' => ' qíng', + '甕' => ' wèng', + '生' => ' shēng', + '甞' => ' cháng', + '甝' => ' hán', + '甜' => ' tián', + '甛' => ' tián', + '甚' => ' shén', + '甙' => ' dài', + '甘' => ' gān', + '甗' => ' yǎn', + '甖' => ' yīng', + '璎' => ' yīng', + '璌' => ' yín', + '玽' => ' gǒu', + '珽' => ' tǐng', + '琇' => ' xiù', + '理' => ' lǐ', + '琅' => ' láng', + '琄' => ' xuàn', + '球' => ' qiú', + '琂' => ' yán', + '琁' => ' xuán', + '琀' => ' hán', + '珿' => ' chù', + '現' => ' xiàn', + '珼' => ' bèi', + '琉' => ' liú', + '珻' => ' méi', + '珺' => ' jùn', + '珹' => ' chéng', + '珸' => ' wú', + '珷' => ' wǔ', + '珶' => ' dì', + '珵' => ' chéng', + '珴' => ' é', + '珳' => ' wén', + '珲' => ' huī', + '琈' => ' fú', + '琊' => ' yá', + '珰' => ' dāng', + '琗' => ' sè', + '琡' => ' chù', + '琠' => ' tiǎn', + '琟' => ' wéi', + '琞' => ' shèng', + '琝' => ' wén', + '琜' => ' lái', + '琛' => ' chēn', + '琚' => ' jū', + '琙' => ' yù', + '琘' => ' mín', + '琖' => ' zhǎn', + '琋' => ' xī', + '琕' => ' pín', + '琔' => ' diàn', + '琓' => ' wán', + '琒' => ' feng', + '琑' => ' suo', + '琐' => ' suǒ', + '琏' => ' liǎn', + '琎' => ' jìn', + '琍' => ' lí', + '琌' => ' líng', + '珱' => ' ying', + '珯' => ' lao', + '琣' => ' běng', + '珉' => ' mín', + '珓' => ' jiào', + '珒' => ' jīn', + '珑' => ' lóng', + '珐' => ' fà', + '珏' => ' jué', + '珎' => ' zhēn', + '珍' => ' zhēn', + '珌' => ' bì', + '珋' => ' liǔ', + '珊' => ' shān', + '珈' => ' jiā', + '珕' => ' lì', + '珇' => ' zǔ', + '珆' => ' yí', + '珅' => ' shēn', + '珄' => ' shēng', + '珃' => ' rǎn', + '珂' => ' kē', + '珁' => ' cí', + '珀' => ' pò', + '玿' => ' sháo', + '玾' => ' jiǎ', + '珔' => ' jiàn', + '珖' => ' guàng', + '珮' => ' pèi', + '珣' => ' xún', + '班' => ' bān', + '珬' => ' xù', + '珫' => ' chōng', + '珪' => ' guī', + '珩' => ' háng', + '珨' => ' xiá', + '珧' => ' yáo', + '珦' => ' xiàng', + '珥' => ' ěr', + '珤' => ' bǎo', + '珢' => ' yín', + '珗' => ' xiān', + '珡' => ' qín', + '珠' => ' zhū', + '珟' => ' sù', + '珞' => ' luò', + '珝' => ' xǔ', + '珜' => ' yáng', + '珛' => ' xiù', + '珚' => ' yān', + '珙' => ' gǒng', + '珘' => ' zhōu', + '琢' => ' zuó', + '琤' => ' chēng', + '璋' => ' zhāng', + '瑦' => ' wǔ', + '瑰' => ' guī', + '瑯' => ' láng', + '瑮' => ' lì', + '瑭' => ' táng', + '瑬' => ' liú', + '瑫' => ' tāo', + '瑪' => ' mǎ', + '瑩' => ' yíng', + '瑨' => ' jìn', + '瑧' => ' zhēn', + '瑥' => ' wēn', + '瑲' => ' qiāng', + '瑤' => ' yáo', + '瑣' => ' suǒ', + '瑢' => ' róng', + '瑡' => ' shī', + '瑠' => ' liú', + '瑟' => ' sè', + '瑞' => ' ruì', + '瑝' => ' huáng', + '瑜' => ' yú', + '瑛' => ' yīng', + '瑱' => ' zhèn', + '瑳' => ' cuō', + '瑙' => ' nǎo', + '璀' => ' cuǐ', + '璊' => ' mén', + '璉' => ' liǎn', + '璈' => ' áo', + '璇' => ' xuán', + '璆' => ' qiú', + '璅' => ' suǒ', + '璄' => ' yǐng', + '璃' => ' lí', + '璂' => ' qí', + '璁' => ' cōng', + '瑿' => ' yī', + '瑴' => ' jué', + '瑾' => ' jǐn', + '瑽' => ' cōng', + '瑼' => ' zhuān', + '瑻' => ' kūn', + '瑺' => ' cháng', + '瑹' => ' shū', + '瑸' => ' bīn', + '瑷' => ' ài', + '瑶' => ' yáo', + '瑵' => ' zhǎo', + '瑚' => ' hú', + '瑘' => ' yá', + '琥' => ' hǔ', + '琱' => ' diāo', + '琻' => ' jin', + '琺' => ' fà', + '琹' => ' qín', + '琸' => ' zhuó', + '琷' => ' què', + '琶' => ' pá', + '琵' => ' pí', + '琴' => ' qín', + '琳' => ' lín', + '琲' => ' bèi', + '琰' => ' yǎn', + '琽' => ' dǔ', + '琯' => ' guǎn', + '琮' => ' cóng', + '琭' => ' lù', + '琬' => ' wǎn', + '琫' => ' běng', + '琪' => ' qí', + '琩' => ' chāng', + '琨' => ' kūn', + '琧' => ' è', + '琦' => ' qí', + '琼' => ' qióng', + '琾' => ' jiè', + '瑗' => ' yuàn', + '瑌' => ' ruǎn', + '瑖' => ' duàn', + '瑕' => ' xiá', + '瑔' => ' quán', + '瑓' => ' liàn', + '瑒' => ' chàng', + '瑑' => ' zhuàn', + '瑐' => ' jiǎn', + '瑏' => ' chuān', + '瑎' => ' xié', + '瑍' => ' huàn', + '瑋' => ' wěi', + '琿' => ' hún', + '瑊' => ' jiān', + '瑉' => ' mín', + '瑈' => ' róu', + '瑇' => ' dài', + '瑆' => ' xīng', + '瑅' => ' tí', + '瑄' => ' xuān', + '瑃' => ' chūn', + '瑂' => ' méi', + '瑁' => ' mào', + '瑀' => ' yǔ', + '薢' => ' xiè', + '诞' => ' dàn', + '薤' => ' xiè', + '雹' => ' báo', + '霃' => ' chén', + '霂' => ' mù', + '霁' => ' jì', + '需' => ' xū', + '雿' => ' diào', + '雾' => ' wù', + '雽' => ' hù', + '雼' => ' dàng', + '電' => ' diàn', + '雺' => ' wù', + '雸' => ' án', + '霅' => ' zhà', + '雷' => ' léi', + '零' => ' líng', + '雵' => ' yāng', + '雴' => ' chì', + '雳' => ' lì', + '雲' => ' yún', + '雱' => ' pāng', + '雰' => ' fēn', + '雯' => ' wén', + '雮' => ' mù', + '霄' => ' xiāo', + '霆' => ' tíng', + '雬' => ' fǒu', + '霓' => ' ní', + '霝' => ' líng', + '霜' => ' shuāng', + '霛' => ' líng', + '霚' => ' wù', + '霙' => ' yīng', + '霘' => ' dòng', + '霗' => ' ling', + '霖' => ' lín', + '霕' => ' tún', + '霔' => ' zhù', + '霒' => ' yīn', + '震' => ' zhèn', + '霑' => ' zhān', + '霐' => ' hóng', + '霏' => ' fēi', + '霎' => ' shà', + '霍' => ' huò', + '霌' => ' zhōu', + '霋' => ' qī', + '霊' => ' líng', + '霉' => ' méi', + '霈' => ' pèi', + '雭' => ' sè', + '雫' => ' nǎ', + '霟' => ' hóng', + '雅' => ' yǎ', + '雏' => ' chú', + '雎' => ' jū', + '雍' => ' yōng', + '雌' => ' cí', + '雋' => ' juàn', + '雊' => ' gòu', + '雉' => ' zhì', + '雈' => ' huán', + '雇' => ' gù', + '集' => ' jí', + '雄' => ' xióng', + '雑' => ' zá', + '雃' => ' qiān', + '雂' => ' qín', + '雁' => ' yàn', + '雀' => ' què', + '隿' => ' yì', + '难' => ' nán', + '隽' => ' juàn', + '隼' => ' sǔn', + '隻' => ' zhī', + '隺' => ' hú', + '雐' => ' hū', + '雒' => ' luò', + '雪' => ' xuě', + '雟' => ' xī', + '雩' => ' yú', + '雨' => ' yǔ', + '雧' => ' jí', + '雦' => ' jí', + '雥' => ' zá', + '雤' => ' xué', + '難' => ' nán', + '離' => ' lí', + '雡' => ' liù', + '雠' => ' chóu', + '雞' => ' jī', + '雓' => ' yú', + '雝' => ' yōng', + '雜' => ' zá', + '雛' => ' chú', + '雚' => ' guàn', + '雙' => ' shuāng', + '雘' => ' wò', + '雗' => ' hàn', + '雖' => ' suī', + '雕' => ' diāo', + '雔' => ' chóu', + '霞' => ' xiá', + '霠' => ' yīn', + '隸' => ' lì', + '靡' => ' mí', + '靫' => ' chá', + '靪' => ' dīng', + '革' => ' gé', + '靨' => ' yè', + '靧' => ' huì', + '靦' => ' tiǎn', + '靥' => ' yè', + '靤' => ' bào', + '靣' => ' miàn', + '面' => ' miàn', + '靠' => ' kào', + '靭' => ' rèn', + '靟' => ' fēi', + '非' => ' fēi', + '靝' => ' tiān', + '靜' => ' jìng', + '靛' => ' diàn', + '靚' => ' jìng', + '静' => ' jìng', + '靘' => ' qìng', + '靗' => ' chēng', + '靖' => ' jìng', + '靬' => ' qián', + '靮' => ' dí', + '靔' => ' tiān', + '靻' => ' zǔ', + '鞅' => ' yāng', + '鞄' => ' páo', + '鞃' => ' hóng', + '鞂' => ' jiá', + '鞁' => ' bèi', + '鞀' => ' táo', + '靿' => ' yào', + '靾' => ' yì', + '靽' => ' bàn', + '靼' => ' dá', + '靺' => ' mò', + '靯' => ' dù', + '靹' => ' nà', + '靸' => ' sǎ', + '靷' => ' yǐn', + '靶' => ' bǎ', + '靵' => ' niǔ', + '靴' => ' xuē', + '靳' => ' jìn', + '靲' => ' qín', + '靱' => ' rèn', + '靰' => ' wù', + '靕' => ' zhēn', + '靓' => ' jìng', + '霡' => ' mài', + '霭' => ' ǎi', + '霷' => ' yáng', + '霶' => ' pāng', + '霵' => ' jí', + '霴' => ' dài', + '霳' => ' lóng', + '露' => ' lù', + '霱' => ' yù', + '霰' => ' sǎn', + '霯' => ' tèng', + '霮' => ' dàn', + '霬' => ' yì', + '霹' => ' pī', + '霫' => ' xí', + '霪' => ' yín', + '霩' => ' kuò', + '霨' => ' wèi', + '霧' => ' wù', + '霦' => ' bīn', + '霥' => ' mèng', + '霤' => ' liù', + '霣' => ' yǔn', + '霢' => ' mài', + '霸' => ' bà', + '霺' => ' wéi', + '青' => ' qīng', + '靇' => ' lóng', + '靑' => ' qīng', + '靐' => ' bìng', + '靏' => ' hè', + '靎' => ' hè', + '靍' => ' he', + '靌' => ' bǎo', + '靋' => ' lì', + '靊' => ' fēng', + '靉' => ' ài', + '靈' => ' líng', + '靆' => ' dài', + '霻' => ' fēng', + '靅' => ' fèi', + '靄' => ' ǎi', + '靃' => ' huò', + '靂' => ' lì', + '靁' => ' léi', + '靀' => ' méng', + '霿' => ' méng', + '霾' => ' mái', + '霽' => ' jì', + '霼' => ' xì', + '隹' => ' zhuī', + '隷' => ' lì', + '鞇' => ' yīn', + '阩' => ' shēng', + '阳' => ' yáng', + '防' => ' fáng', + '阱' => ' jǐng', + '阰' => ' pí', + '阯' => ' zhǐ', + '阮' => ' ruǎn', + '阭' => ' yǔn', + '阬' => ' kēng', + '阫' => ' péi', + '阪' => ' bǎn', + '阨' => ' è', + '阵' => ' zhèn', + '阧' => ' dǒu', + '阦' => ' yáng', + '阥' => ' yīn', + '阤' => ' zhì', + '阣' => ' gài', + '阢' => ' wù', + '阡' => ' qiān', + '阠' => ' xìn', + '队' => ' duì', + '阞' => ' lè', + '阴' => ' yīn', + '阶' => ' jiē', + '阜' => ' fù', + '陃' => ' bǐng', + '降' => ' jiàng', + '陌' => ' mò', + '陋' => ' lòu', + '陊' => ' duò', + '陉' => ' xíng', + '陈' => ' chén', + '陇' => ' lǒng', + '陆' => ' lù', + '际' => ' jì', + '附' => ' fù', + '陂' => ' bēi', + '阷' => ' chēng', + '陁' => ' tuó', + '陀' => ' tuó', + '阿' => ' ā', + '阾' => ' lǐng', + '阽' => ' diàn', + '阼' => ' zuò', + '阻' => ' zǔ', + '阺' => ' dǐ', + '阹' => ' qū', + '阸' => ' è', + '阝' => ' fù', + '阛' => ' huán', + '陏' => ' duò', + '闵' => ' mǐn', + '闿' => ' kǎi', + '闾' => ' lǘ', + '闽' => ' mǐn', + '闼' => ' tà', + '闻' => ' wén', + '闺' => ' guī', + '闹' => ' nào', + '闸' => ' zhá', + '闷' => ' mèn', + '闶' => ' kāng', + '间' => ' jiān', + '阁' => ' gé', + '闳' => ' hóng', + '闲' => ' xián', + '闱' => ' wéi', + '闰' => ' rùn', + '闯' => ' chuǎng', + '问' => ' wèn', + '闭' => ' bì', + '闬' => ' hàn', + '闫' => ' yàn', + '闪' => ' shǎn', + '阀' => ' fá', + '阂' => ' hé', + '阚' => ' hǎn', + '阏' => ' è', + '阙' => ' quē', + '阘' => ' dá', + '阗' => ' tián', + '阖' => ' hé', + '阕' => ' què', + '阔' => ' kuò', + '阓' => ' huì', + '阒' => ' qù', + '阑' => ' lán', + '阐' => ' chǎn', + '阎' => ' yán', + '阃' => ' kǔn', + '阍' => ' hūn', + '阌' => ' wén', + '阋' => ' xì', + '阊' => ' chāng', + '阉' => ' yān', + '阈' => ' yù', + '阇' => ' dū', + '阆' => ' láng', + '阅' => ' yuè', + '阄' => ' jiū', + '陎' => ' shū', + '限' => ' xiàn', + '隶' => ' lì', + '隑' => ' gài', + '際' => ' jì', + '隚' => ' táng', + '隙' => ' xì', + '隘' => ' ài', + '隗' => ' kuí', + '隖' => ' wù', + '隕' => ' yǔn', + '隔' => ' gé', + '隓' => ' huī', + '隒' => ' yǎn', + '隐' => ' yǐn', + '隝' => ' dǎo', + '随' => ' suí', + '階' => ' jiē', + '隍' => ' huáng', + '隌' => ' ǎn', + '隋' => ' suí', + '隊' => ' duì', + '隉' => ' niè', + '隈' => ' wēi', + '隇' => ' wēi', + '隆' => ' lóng', + '障' => ' zhàng', + '隞' => ' áo', + '隄' => ' dī', + '隫' => ' fén', + '隵' => ' xī', + '隴' => ' lǒng', + '隳' => ' huī', + '隲' => ' é', + '隱' => ' yǐn', + '隰' => ' xí', + '隯' => ' dǎo', + '隮' => ' jī', + '隭' => ' ér', + '隬' => ' nǐ', + '險' => ' xiǎn', + '隟' => ' xì', + '隩' => ' ào', + '隨' => ' suí', + '隧' => ' suì', + '隦' => ' jiǎo', + '隥' => ' dèng', + '隤' => ' tuí', + '隣' => ' lín', + '隢' => ' rǎo', + '隡' => ' sa', + '隠' => ' yǐn', + '隅' => ' yú', + '隃' => ' shù', + '陑' => ' ér', + '陝' => ' shǎn', + '陧' => ' niè', + '陦' => ' dao', + '陥' => ' xiàn', + '除' => ' chú', + '陣' => ' zhèn', + '院' => ' yuàn', + '陡' => ' dǒu', + '陠' => ' pū', + '陟' => ' zhì', + '陞' => ' shēng', + '陜' => ' xiá', + '险' => ' xiǎn', + '陛' => ' bì', + '陚' => ' fù', + '陙' => ' chún', + '陘' => ' xíng', + '陗' => ' qiào', + '陖' => ' jùn', + '陕' => ' shǎn', + '陔' => ' gāi', + '陓' => ' yū', + '陒' => ' guǐ', + '陨' => ' yǔn', + '陪' => ' péi', + '隂' => ' yīn', + '陷' => ' xiàn', + '隁' => ' yàn', + '隀' => ' chóng', + '陿' => ' xiá', + '陾' => ' réng', + '陽' => ' yáng', + '陼' => ' zhǔ', + '陻' => ' yīn', + '険' => ' xiǎn', + '陹' => ' shēng', + '陸' => ' lù', + '陶' => ' táo', + '陫' => ' fèi', + '陵' => ' líng', + '陴' => ' pí', + '陳' => ' chén', + '陲' => ' chuí', + '陱' => ' jū', + '陰' => ' yīn', + '陯' => ' lún', + '陮' => ' duì', + '陭' => ' yì', + '陬' => ' zōu', + '鞆' => ' bing', + '鞈' => ' gé', + '门' => ' mén', + '颙' => ' yóng', + '颣' => ' lèi', + '颢' => ' hào', + '颡' => ' sǎng', + '颠' => ' diān', + '颟' => ' mān', + '颞' => ' niè', + '额' => ' é', + '颜' => ' yán', + '颛' => ' zhuān', + '颚' => ' è', + '题' => ' tí', + '颥' => ' rú', + '颗' => ' kē', + '颖' => ' yǐng', + '颕' => ' yǐng', + '颔' => ' hàn', + '颓' => ' tuí', + '颒' => ' huì', + '频' => ' pín', + '颐' => ' yí', + '颏' => ' kē', + '颎' => ' jiǒng', + '颤' => ' chàn', + '颦' => ' pín', + '颌' => ' hé', + '颳' => ' guā', + '颽' => ' kǎi', + '颼' => ' sōu', + '颻' => ' yáo', + '颺' => ' yáng', + '颹' => ' wěi', + '颸' => ' sī', + '颷' => ' biāo', + '颶' => ' jù', + '颵' => ' shāo', + '颴' => ' xuàn', + '颲' => ' liè', + '颧' => ' quán', + '颱' => ' tái', + '颰' => ' bá', + '颯' => ' sà', + '颮' => ' biāo', + '颭' => ' zhǎn', + '颬' => ' xiā', + '颫' => ' fú', + '颪' => ' gua', + '颩' => ' biāo', + '風' => ' fēng', + '颍' => ' yǐng', + '颋' => ' tǐng', + '颿' => ' fān', + '顥' => ' hào', + '顯' => ' xiǎn', + '顮' => ' bīn', + '顭' => ' méng', + '顬' => ' rú', + '顫' => ' chàn', + '顪' => ' huì', + '顩' => ' yǎn', + '顨' => ' xùn', + '顧' => ' gù', + '顦' => ' qiáo', + '顤' => ' yáo', + '顱' => ' lú', + '顣' => ' cù', + '顢' => ' mán', + '顡' => ' wài', + '顠' => ' piǎo', + '顟' => ' láo', + '類' => ' lèi', + '顝' => ' kuī', + '顜' => ' jiǎng', + '顛' => ' diān', + '顚' => ' diān', + '顰' => ' pín', + '顲' => ' lǎn', + '颊' => ' jiá', + '顿' => ' dùn', + '颉' => ' jié', + '颈' => ' jǐng', + '颇' => ' pō', + '领' => ' lǐng', + '颅' => ' lú', + '预' => ' yù', + '颃' => ' háng', + '颂' => ' sòng', + '颁' => ' bān', + '颀' => ' qí', + '顾' => ' gù', + '顳' => ' niè', + '顽' => ' wán', + '顼' => ' xū', + '须' => ' xū', + '顺' => ' shùn', + '项' => ' xiàng', + '顸' => ' hān', + '顷' => ' qǐng', + '顶' => ' dǐng', + '页' => ' yè', + '顴' => ' quán', + '颾' => ' sōu', + '飀' => ' liú', + '願' => ' yuàn', + '餁' => ' rèn', + '餋' => ' juàn', + '養' => ' yǎng', + '餉' => ' xiǎng', + '餈' => ' cí', + '餇' => ' tóng', + '餆' => ' yáo', + '餅' => ' bǐng', + '餄' => ' jiá', + '餃' => ' jiǎo', + '餂' => ' tiǎn', + '餀' => ' hài', + '餍' => ' yàn', + '飿' => ' duò', + '飾' => ' shì', + '飽' => ' bǎo', + '飼' => ' sì', + '飻' => ' tiè', + '飺' => ' cí', + '飹' => ' liǔ', + '飸' => ' tāo', + '飷' => ' jiě', + '飶' => ' bì', + '餌' => ' ěr', + '餎' => ' le', + '飴' => ' yí', + '餛' => ' hún', + '餥' => ' fēi', + '餤' => ' tán', + '餣' => ' yè', + '餢' => ' bù', + '餡' => ' xiàn', + '餠' => ' bǐng', + '餟' => ' zhuì', + '餞' => ' jiàn', + '餝' => ' shì', + '餜' => ' guǒ', + '餚' => ' yáo', + '餏' => ' xī', + '餙' => ' shì', + '餘' => ' yú', + '餗' => ' sù', + '餖' => ' dòu', + '餕' => ' jùn', + '餔' => ' bù', + '餓' => ' è', + '餒' => ' něi', + '餑' => ' bō', + '餐' => ' cān', + '飵' => ' zuò', + '飳' => ' tǒu', + '飁' => ' xí', + '飍' => ' xiū', + '飗' => ' liú', + '飖' => ' yáo', + '飕' => ' sōu', + '飔' => ' sī', + '飓' => ' jù', + '飒' => ' sà', + '飑' => ' biāo', + '飐' => ' zhǎn', + '飏' => ' yáng', + '风' => ' fēng', + '飌' => ' fēng', + '飙' => ' biāo', + '飋' => ' sè', + '飊' => ' biao', + '飉' => ' liáo', + '飈' => ' biāo', + '飇' => ' biāo', + '飆' => ' biāo', + '飅' => ' liú', + '飄' => ' piāo', + '飃' => ' piāo', + '飂' => ' liù', + '飘' => ' piāo', + '飚' => ' biāo', + '飲' => ' yǐn', + '飧' => ' sūn', + '飱' => ' sūn', + '飰' => ' fàn', + '飯' => ' fàn', + '飮' => ' yǐn', + '飭' => ' chì', + '飬' => ' juàn', + '飫' => ' yù', + '飪' => ' rèn', + '飩' => ' tún', + '飨' => ' xiǎng', + '飦' => ' zhān', + '飛' => ' fēi', + '飥' => ' tuō', + '飤' => ' sì', + '飣' => ' dìng', + '飢' => ' jī', + '飡' => ' cān', + '飠' => ' shí', + '食' => ' shí', + '飞' => ' fēi', + '飝' => ' fēi', + '飜' => ' fān', + '顙' => ' sǎng', + '顗' => ' yǐ', + '鞉' => ' táo', + '韉' => ' jiān', + '韓' => ' hán', + '韒' => ' qiào', + '韑' => ' wěi', + '韐' => ' gé', + '韏' => ' quàn', + '韎' => ' mèi', + '韍' => ' fú', + '韌' => ' rèn', + '韋' => ' wéi', + '韊' => ' lán', + '韈' => ' wà', + '韕' => ' kuo', + '韇' => ' dú', + '韆' => ' qiān', + '韅' => ' xiǎn', + '韄' => ' hù', + '韃' => ' dá', + '韂' => ' chàn', + '韁' => ' jiāng', + '韀' => ' jiān', + '鞿' => ' jī', + '鞾' => ' xuē', + '韔' => ' chàng', + '韖' => ' rǒu', + '鞼' => ' guì', + '韣' => ' dú', + '韭' => ' jiǔ', + '韬' => ' tāo', + '韫' => ' yùn', + '韪' => ' wěi', + '韩' => ' hán', + '韨' => ' fú', + '韧' => ' rèn', + '韦' => ' wéi', + '韥' => ' dú', + '韤' => ' wà', + '韢' => ' suì', + '韗' => ' yùn', + '韡' => ' wěi', + '韠' => ' bì', + '韟' => ' gāo', + '韞' => ' yùn', + '韝' => ' gōu', + '韜' => ' tāo', + '韛' => ' bài', + '韚' => ' gé', + '韙' => ' wěi', + '韘' => ' shè', + '鞽' => ' qiáo', + '鞻' => ' lóu', + '韯' => ' xiān', + '鞕' => ' yìng', + '鞟' => ' kuò', + '鞞' => ' bǐng', + '鞝' => ' shàng', + '鞜' => ' tà', + '鞛' => ' běng', + '鞚' => ' kòng', + '鞙' => ' xuàn', + '鞘' => ' qiào', + '鞗' => ' tiáo', + '鞖' => ' suī', + '鞔' => ' mán', + '鞡' => ' la', + '鞓' => ' tīng', + '鞒' => ' qiáo', + '鞑' => ' dá', + '鞐' => ' qia', + '鞏' => ' gǒng', + '鞎' => ' hén', + '鞍' => ' ān', + '鞌' => ' ān', + '鞋' => ' xié', + '鞊' => ' jié', + '鞠' => ' jū', + '鞢' => ' xiè', + '鞺' => ' tāng', + '鞯' => ' jiān', + '鞹' => ' kuò', + '鞸' => ' bì', + '鞷' => ' gé', + '鞶' => ' pán', + '鞵' => ' xié', + '鞴' => ' bèi', + '鞳' => ' tà', + '鞲' => ' gōu', + '鞱' => ' tāo', + '鞰' => ' wēn', + '鞮' => ' dī', + '鞣' => ' róu', + '鞭' => ' biān', + '鞬' => ' jiān', + '鞫' => ' jū', + '鞪' => ' mù', + '鞩' => ' xiào', + '鞨' => ' hé', + '鞧' => ' qiū', + '鞦' => ' qiū', + '鞥' => ' ēng', + '鞤' => ' bāng', + '韮' => ' jiǔ', + '韰' => ' xiè', + '顖' => ' xìn', + '頱' => ' luō', + '頻' => ' pín', + '頺' => ' tuí', + '頹' => ' tuí', + '頸' => ' jǐng', + '頷' => ' hàn', + '頶' => ' hú', + '頵' => ' yūn', + '頴' => ' yǐng', + '頳' => ' chēng', + '頲' => ' tǐng', + '頰' => ' jiá', + '頽' => ' tuí', + '頯' => ' kuí', + '頮' => ' huì', + '頭' => ' tóu', + '頬' => ' jiá', + '頫' => ' fǔ', + '頪' => ' lèi', + '頩' => ' pīng', + '頨' => ' yǔ', + '頧' => ' duǐ', + '頦' => ' hái', + '頼' => ' lài', + '頾' => ' zī', + '頤' => ' yí', + '顋' => ' sāi', + '顕' => ' xiǎn', + '顔' => ' yán', + '顓' => ' zhuān', + '顒' => ' yóng', + '顑' => ' kǎn', + '顐' => ' wèn', + '顏' => ' yán', + '顎' => ' è', + '額' => ' é', + '題' => ' tí', + '顊' => ' yí', + '頿' => ' zī', + '顉' => ' qīn', + '顈' => ' xuǎn', + '顇' => ' cuì', + '顆' => ' kē', + '顅' => ' qiān', + '顄' => ' hàn', + '顃' => ' tán', + '顂' => ' lài', + '顁' => ' dìng', + '顀' => ' chuí', + '頥' => ' shěn', + '頣' => ' shěn', + '韱' => ' xiān', + '韽' => ' ān', + '頇' => ' hān', + '順' => ' shùn', + '項' => ' xiàng', + '頄' => ' kuí', + '頃' => ' qǐng', + '頂' => ' dǐng', + '頁' => ' yè', + '頀' => ' hù', + '響' => ' xiǎng', + '韾' => ' yīn', + '韼' => ' péng', + '頉' => ' yí', + '韻' => ' yùn', + '韺' => ' yīng', + '韹' => ' huáng', + '韸' => ' péng', + '韷' => ' lè', + '韶' => ' sháo', + '韵' => ' yùn', + '韴' => ' zá', + '音' => ' yīn', + '韲' => ' jī', + '須' => ' xū', + '頊' => ' xū', + '頢' => ' kuò', + '頗' => ' pō', + '頡' => ' xié', + '頠' => ' wěi', + '頟' => ' é', + '頞' => ' è', + '頝' => ' qiāo', + '頜' => ' hé', + '頛' => ' lèi', + '頚' => ' jǐng', + '頙' => ' chè', + '領' => ' lǐng', + '頖' => ' pàn', + '頋' => ' ě', + '頕' => ' dān', + '頔' => ' dí', + '頓' => ' dùn', + '頒' => ' bān', + '頑' => ' wán', + '預' => ' yù', + '頏' => ' háng', + '頎' => ' qí', + '頍' => ' kuǐ', + '頌' => ' sòng', + '闩' => ' shuān', + '闧' => ' tā', + '餧' => ' wèi', + '鎸' => ' juān', + '鏂' => ' ōu', + '鏁' => ' suǒ', + '鏀' => ' lǔ', + '鎿' => ' ná', + '鎾' => ' wen', + '鎽' => ' feng', + '鎼' => ' xià', + '鎻' => ' suǒ', + '鎺' => ' zu', + '鎹' => ' song', + '鎷' => ' mǎ', + '鏄' => ' tuán', + '鎶' => ' gē', + '鎵' => ' jiā', + '鎴' => ' xí', + '鎳' => ' niè', + '鎲' => ' tǎng', + '鎱' => ' yuán', + '鎰' => ' yì', + '鎯' => ' láng', + '鎮' => ' zhèn', + '鎭' => ' zhèn', + '鏃' => ' zú', + '鏅' => ' xiū', + '鎫' => ' wàn', + '鏒' => ' sǎn', + '鏜' => ' tāng', + '鏛' => ' cháng', + '鏚' => ' qī', + '鏙' => ' cuī', + '鏘' => ' qiāng', + '鏗' => ' kēng', + '鏖' => ' áo', + '鏕' => ' lù', + '鏔' => ' yí', + '鏓' => ' zǒng', + '鏑' => ' dí', + '鏆' => ' guàn', + '鏐' => ' liú', + '鏏' => ' wèi', + '鏎' => ' bì', + '鏍' => ' luó', + '鏌' => ' mò', + '鏋' => ' mǎn', + '鏊' => ' ào', + '鏉' => ' shòu', + '鏈' => ' liàn', + '鏇' => ' xuàn', + '鎬' => ' hào', + '鎪' => ' sōu', + '鏞' => ' yōng', + '鎄' => ' āi', + '鎎' => ' kài', + '鎍' => ' suǒ', + '鎌' => ' lián', + '鎋' => ' xiá', + '鎊' => ' bàng', + '鎉' => ' dá', + '鎈' => ' suǒ', + '鎇' => ' méi', + '鎆' => ' qian', + '鎅' => ' jiè', + '鎃' => ' pài', + '鎐' => ' yáo', + '鎂' => ' měi', + '鎁' => ' yé', + '鎀' => ' xiū', + '鍿' => ' zī', + '鍾' => ' zhōng', + '鍽' => ' biān', + '鍼' => ' zhēn', + '鍻' => ' jié', + '鍺' => ' duǒ', + '鍹' => ' xuān', + '鎏' => ' liú', + '鎑' => ' yè', + '鎩' => ' shā', + '鎞' => ' bī', + '鎨' => ' sǔn', + '鎧' => ' kǎi', + '鎦' => ' liú', + '鎥' => ' tiáo', + '鎤' => ' huàng', + '鎣' => ' yíng', + '鎢' => ' wū', + '鎡' => ' zī', + '鎠' => ' gāng', + '鎟' => ' sǎng', + '鎝' => ' dā', + '鎒' => ' nòu', + '鎜' => ' pán', + '鎛' => ' bó', + '鎚' => ' chuí', + '鎙' => ' shuò', + '鎘' => ' lì', + '鎗' => ' qiāng', + '鎖' => ' suǒ', + '鎕' => ' táng', + '鎔' => ' róng', + '鎓' => ' wēng', + '鏝' => ' màn', + '鏟' => ' chǎn', + '鍷' => ' kuí', + '鐠' => ' pǔ', + '鐪' => ' lǔ', + '鐩' => ' suì', + '鐨' => ' fèi', + '鐧' => ' jiān', + '鐦' => ' kāi', + '鐥' => ' shàn', + '鐤' => ' dǐng', + '鐣' => ' zhang', + '鐢' => ' fán', + '鐡' => ' tiě', + '鐟' => ' zān', + '鐬' => ' huì', + '鐞' => ' nòu', + '鐝' => ' jué', + '鐜' => ' duī', + '鐛' => ' yìng', + '鐚' => ' yā', + '鐙' => ' dèng', + '鐘' => ' zhōng', + '鐗' => ' jiǎn', + '鐖' => ' jī', + '鐕' => ' zān', + '鐫' => ' juān', + '鐭' => ' yù', + '鐓' => ' duì', + '鐺' => ' dāng', + '鑄' => ' zhù', + '鑃' => ' diào', + '鑂' => ' xùn', + '鑁' => ' zōng', + '鑀' => ' ài', + '鐿' => ' yì', + '鐾' => ' bèi', + '鐽' => ' dá', + '鐼' => ' fén', + '鐻' => ' jù', + '鐹' => ' guǒ', + '鐮' => ' lián', + '鐸' => ' duó', + '鐷' => ' yè', + '鐶' => ' huán', + '鐵' => ' tiě', + '鐴' => ' bì', + '鐳' => ' léi', + '鐲' => ' zhuó', + '鐱' => ' jiàn', + '鐰' => ' qiāo', + '鐯' => ' zhuó', + '鐔' => ' xín', + '鐒' => ' láo', + '鏠' => ' fēng', + '鏬' => ' xià', + '鏶' => ' jí', + '鏵' => ' huá', + '鏴' => ' lù', + '鏳' => ' chēng', + '鏲' => ' qian', + '鏱' => ' zhang', + '鏰' => ' bèng', + '鏯' => ' shuang', + '鏮' => ' kāng', + '鏭' => ' xī', + '鏫' => ' lí', + '鏸' => ' huì', + '鏪' => ' cáo', + '鏩' => ' jiàn', + '鏨' => ' zàn', + '鏧' => ' lóng', + '鏦' => ' cōng', + '鏥' => ' xiù', + '鏤' => ' lòu', + '鏣' => ' shù', + '鏢' => ' biāo', + '鏡' => ' jìng', + '鏷' => ' pú', + '鏹' => ' qiǎng', + '鐑' => ' qiè', + '鐆' => ' suì', + '鐐' => ' liáo', + '鐏' => ' zūn', + '鐎' => ' jiāo', + '鐍' => ' jué', + '鐌' => ' xiàng', + '鐋' => ' tāng', + '鐊' => ' yáng', + '鐉' => ' quān', + '鐈' => ' qiáo', + '鐇' => ' fán', + '鐅' => ' piě', + '鏺' => ' pō', + '鐄' => ' huáng', + '鐃' => ' náo', + '鐂' => ' liù', + '鐁' => ' sī', + '鐀' => ' kuì', + '鏿' => ' chēng', + '鏾' => ' sǎn', + '鏽' => ' xiù', + '鏼' => ' sè', + '鏻' => ' lín', + '鍸' => ' hú', + '鍶' => ' sōng', + '鑆' => ' zhuì', + '鋨' => ' tiě', + '鋲' => ' bing', + '鋱' => ' tè', + '鋰' => ' lǐ', + '鋯' => ' gào', + '鋮' => ' chéng', + '鋭' => ' ruì', + '鋬' => ' pàn', + '鋫' => ' lí', + '鋪' => ' pù', + '鋩' => ' máng', + '鋧' => ' xiàn', + '鋴' => ' zhen', + '鋦' => ' jū', + '鋥' => ' zèng', + '鋤' => ' chú', + '鋣' => ' yé', + '鋢' => ' lüè', + '鋡' => ' hán', + '鋠' => ' shèn', + '鋟' => ' qǐn', + '鋞' => ' xíng', + '鋝' => ' lüè', + '鋳' => ' zhù', + '鋵' => ' tū', + '鋛' => ' gǒng', + '錂' => ' líng', + '錌' => ' àn', + '錋' => ' péng', + '錊' => ' zuì', + '錉' => ' mín', + '錈' => ' juǎn', + '錇' => ' póu', + '錆' => ' qiāng', + '錅' => ' lí', + '錄' => ' lù', + '錃' => ' bēi', + '錁' => ' guǒ', + '鋶' => ' liǔ', + '錀' => ' lún', + '鋿' => ' cháng', + '鋾' => ' táo', + '鋽' => ' diào', + '鋼' => ' gāng', + '鋻' => ' jiàn', + '鋺' => ' yuǎn', + '鋹' => ' chǎng', + '鋸' => ' jù', + '鋷' => ' zuì', + '鋜' => ' zhuó', + '鋚' => ' tiáo', + '錎' => ' xiàn', + '銴' => ' shì', + '銾' => ' hòng', + '銽' => ' guā', + '銼' => ' cuò', + '銻' => ' tí', + '銺' => ' zàng', + '銹' => ' xiù', + '銸' => ' zhé', + '銷' => ' xiāo', + '銶' => ' qiú', + '銵' => ' kēng', + '銳' => ' ruì', + '鋀' => ' tōu', + '銲' => ' hàn', + '銱' => ' diào', + '銰' => ' āi', + '銯' => ' si', + '銮' => ' luán', + '銭' => ' qián', + '銬' => ' kào', + '銫' => ' sè', + '銪' => ' yǒu', + '銩' => ' diū', + '銿' => ' zhōng', + '鋁' => ' lǚ', + '鋙' => ' yǔ', + '鋎' => ' hàn', + '鋘' => ' huá', + '鋗' => ' xuān', + '鋖' => ' sī', + '鋕' => ' zhì', + '鋔' => ' wǎn', + '鋓' => ' chān', + '鋒' => ' fēng', + '鋑' => ' cuān', + '鋐' => ' hóng', + '鋏' => ' jiá', + '鋍' => ' bó', + '鋂' => ' méi', + '鋌' => ' dìng', + '鋋' => ' chán', + '鋊' => ' yù', + '鋉' => ' sù', + '鋈' => ' wù', + '鋇' => ' bèi', + '鋆' => ' yún', + '鋅' => ' xīn', + '鋄' => ' wǎn', + '鋃' => ' láng', + '錍' => ' pī', + '錏' => ' yā', + '鍵' => ' jiàn', + '鍐' => ' zōng', + '鍚' => ' yáng', + '鍙' => ' hù', + '鍘' => ' zhá', + '鍗' => ' tí', + '鍖' => ' chěn', + '鍕' => ' jūn', + '鍔' => ' è', + '鍓' => ' jí', + '鍒' => ' róu', + '鍑' => ' fù', + '鍏' => ' wéi', + '鍜' => ' xiá', + '鍎' => ' tú', + '鍍' => ' dù', + '鍌' => ' xiǎn', + '鍋' => ' guō', + '鍊' => ' liàn', + '鍉' => ' dī', + '鍈' => ' yīng', + '鍇' => ' kǎi', + '鍆' => ' mén', + '鍅' => ' fa', + '鍛' => ' duàn', + '鍝' => ' yú', + '鍃' => ' huō', + '鍪' => ' móu', + '鍴' => ' duān', + '鍳' => ' jiàn', + '鍲' => ' mín', + '鍱' => ' yè', + '鍰' => ' huán', + '鍯' => ' cōng', + '鍮' => ' tōu', + '鍭' => ' hóu', + '鍬' => ' qiāo', + '鍫' => ' qiāo', + '鍩' => ' tiǎn', + '鍞' => ' kēng', + '鍨' => ' kuí', + '鍧' => ' hōng', + '鍦' => ' shī', + '鍥' => ' qiè', + '鍤' => ' chā', + '鍣' => ' zhāo', + '鍢' => ' fù', + '鍡' => ' wěi', + '鍠' => ' huáng', + '鍟' => ' xīng', + '鍄' => ' liàng', + '鍂' => ' piān', + '錐' => ' zhuī', + '錜' => ' niè', + '錦' => ' jǐn', + '錥' => ' yù', + '錤' => ' jī', + '錣' => ' zhuì', + '錢' => ' qián', + '錡' => ' qí', + '錠' => ' dìng', + '錟' => ' tán', + '錞' => ' chún', + '錝' => ' zòng', + '錛' => ' bēn', + '錨' => ' máo', + '錚' => ' zhēng', + '錙' => ' zī', + '錘' => ' chuí', + '錗' => ' nèi', + '錖' => ' dú', + '錕' => ' kūn', + '錔' => ' tà', + '錓' => ' kōng', + '錒' => ' kē', + '錑' => ' lèi', + '錧' => ' guǎn', + '錩' => ' chāng', + '鍁' => ' xiān', + '錶' => ' biǎo', + '鍀' => ' dé', + '錿' => ' hu', + '錾' => ' zàn', + '錽' => ' wàn', + '錼' => ' nài', + '錻' => ' wu', + '錺' => ' fang', + '錹' => ' kěn', + '錸' => ' lái', + '錷' => ' gá', + '錵' => ' huā', + '錪' => ' tiǎn', + '錴' => ' lù', + '錳' => ' měng', + '録' => ' lù', + '錱' => ' zhēn', + '錰' => ' shù', + '錯' => ' cuò', + '錮' => ' gù', + '錭' => ' táo', + '錬' => ' liàn', + '錫' => ' xī', + '鑅' => ' héng', + '鑇' => ' jī', + '闦' => ' wén', + '镙' => ' luó', + '镣' => ' liào', + '镢' => ' jué', + '镡' => ' chán', + '镠' => ' liú', + '镟' => ' xuàn', + '镞' => ' zú', + '镝' => ' dī', + '镜' => ' jìng', + '镛' => ' yōng', + '镚' => ' bèng', + '镘' => ' màn', + '镥' => ' lǔ', + '镗' => ' tāng', + '镖' => ' biāo', + '镕' => ' róng', + '镔' => ' bīn', + '镓' => ' jiā', + '镒' => ' yì', + '镑' => ' bàng', + '镐' => ' gǎo', + '镏' => ' liú', + '镎' => ' ná', + '镤' => ' pú', + '镦' => ' duì', + '镌' => ' juān', + '镳' => ' biāo', + '镽' => ' liǎo', + '镼' => ' qū', + '镻' => ' dié', + '镺' => ' ǎo', + '镹' => ' jiǔ', + '镸' => ' cháng', + '長' => ' zhǎng', + '镶' => ' xiāng', + '镵' => ' chán', + '镴' => ' là', + '镲' => ' chǎ', + '镧' => ' lán', + '镱' => ' yì', + '镰' => ' lián', + '镯' => ' zhuó', + '镮' => ' huán', + '镭' => ' léi', + '镬' => ' huò', + '镫' => ' dèng', + '镪' => ' qiāng', + '镩' => ' cuān', + '镨' => ' pǔ', + '镍' => ' niè', + '镋' => ' tǎng', + '长' => ' zhǎng', + '锥' => ' zhuī', + '锯' => ' jù', + '键' => ' jiàn', + '锭' => ' dìng', + '锬' => ' tán', + '锫' => ' péi', + '锪' => ' huō', + '锩' => ' juǎn', + '锨' => ' xiān', + '锧' => ' zhì', + '锦' => ' jǐn', + '锤' => ' chuí', + '锱' => ' zī', + '锣' => ' luó', + '锢' => ' gù', + '锡' => ' xī', + '锠' => ' chāng', + '锟' => ' kūn', + '锞' => ' kè', + '锝' => ' dé', + '锜' => ' qí', + '锛' => ' bēn', + '锚' => ' máo', + '锰' => ' měng', + '锲' => ' qiè', + '镊' => ' niè', + '锿' => ' āi', + '镉' => ' gé', + '镈' => ' bó', + '镇' => ' zhèn', + '镆' => ' mò', + '镅' => ' méi', + '镄' => ' fèi', + '镃' => ' zī', + '镂' => ' lòu', + '镁' => ' měi', + '镀' => ' dù', + '锾' => ' huán', + '锳' => ' yīng', + '锽' => ' huáng', + '锼' => ' sōu', + '锻' => ' duàn', + '锺' => ' zhōng', + '锹' => ' qiāo', + '锸' => ' chā', + '锷' => ' è', + '锶' => ' sī', + '锵' => ' qiāng', + '锴' => ' kǎi', + '镾' => ' mí', + '門' => ' mén', + '锘' => ' nuò', + '闁' => ' bāo', + '闋' => ' què', + '闊' => ' kuò', + '闉' => ' yīn', + '闈' => ' wéi', + '闇' => ' àn', + '闆' => ' bǎn', + '闅' => ' wén', + '闄' => ' yǎo', + '闃' => ' qù', + '闂' => ' hòng', + '闀' => ' xiàng', + '闍' => ' dū', + '閿' => ' wén', + '閾' => ' yù', + '閽' => ' hūn', + '閼' => ' è', + '閻' => ' yán', + '閺' => ' wén', + '閹' => ' yān', + '閸' => ' kǔn', + '閷' => ' shài', + '閶' => ' chāng', + '闌' => ' lán', + '闎' => ' quan', + '閴' => ' qù', + '闛' => ' táng', + '闥' => ' tà', + '闤' => ' huán', + '闣' => ' dàng', + '闢' => ' pì', + '闡' => ' chǎn', + '闠' => ' huì', + '闟' => ' xì', + '闞' => ' kàn', + '闝' => ' piáo', + '關' => ' guān', + '闚' => ' kuī', + '闏' => ' fēng', + '闙' => ' qǐ', + '闘' => ' dòu', + '闗' => ' guān', + '闖' => ' chuǎng', + '闕' => ' què', + '闔' => ' hé', + '闓' => ' kǎi', + '闒' => ' tà', + '闑' => ' niè', + '闐' => ' tián', + '閵' => ' lìn', + '閳' => ' chǎn', + '閁' => ' mà', + '閍' => ' bēng', + '閗' => ' dòu', + '閖' => ' shui', + '閕' => ' xiā', + '閔' => ' mǐn', + '間' => ' jiān', + '閒' => ' xián', + '閑' => ' xián', + '閐' => ' sàn', + '閏' => ' rùn', + '閎' => ' hóng', + '閌' => ' kàng', + '閙' => ' nào', + '開' => ' kāi', + '閊' => ' shan', + '閉' => ' bì', + '閈' => ' hàn', + '閇' => ' bì', + '閆' => ' yán', + '閅' => ' mén', + '閄' => ' huò', + '閃' => ' shǎn', + '閂' => ' shuān', + '閘' => ' zhá', + '閚' => ' zhān', + '閲' => ' yuè', + '閧' => ' hòng', + '閱' => ' yuè', + '閰' => ' jú', + '閯' => ' shà', + '閮' => ' tíng', + '閭' => ' lǘ', + '閬' => ' làng', + '閫' => ' kǔn', + '閪' => ' sē', + '閩' => ' mǐn', + '閨' => ' guī', + '閦' => ' chù', + '閛' => ' pēng', + '閥' => ' fá', + '閤' => ' gé', + '閣' => ' gé', + '関' => ' guān', + '閡' => ' ài', + '閠' => ' rùn', + '閟' => ' bì', + '閞' => ' biàn', + '閝' => ' líng', + '閜' => ' xiǎ', + '错' => ' cuò', + '锗' => ' zhě', + '鑈' => ' niè', + '针' => ' zhēn', + '钒' => ' fán', + '钑' => ' jí', + '钐' => ' shān', + '钏' => ' chuàn', + '钎' => ' qiān', + '钍' => ' tǔ', + '钌' => ' liǎo', + '钋' => ' pō', + '钊' => ' zhāo', + '钉' => ' dīng', + '钇' => ' yǐ', + '钔' => ' mén', + '钆' => ' gá', + '钅' => ' jīn', + '钄' => ' lán', + '钃' => ' shǔ', + '钂' => ' tǎng', + '钁' => ' jué', + '钀' => ' niè', + '鑿' => ' záo', + '鑾' => ' luán', + '鑽' => ' zuān', + '钓' => ' diào', + '钕' => ' nǚ', + '鑻' => ' pàn', + '钢' => ' gāng', + '钬' => ' huǒ', + '钫' => ' fāng', + '钪' => ' kàng', + '钩' => ' gōu', + '钨' => ' wū', + '钧' => ' jūn', + '钦' => ' qīn', + '钥' => ' yào', + '钤' => ' qián', + '钣' => ' bǎn', + '钡' => ' bèi', + '钖' => ' yáng', + '钠' => ' nà', + '钟' => ' zhōng', + '钞' => ' chāo', + '钝' => ' dùn', + '钜' => ' jù', + '钛' => ' tài', + '钚' => ' bù', + '钙' => ' gài', + '钘' => ' xíng', + '钗' => ' chāi', + '鑼' => ' luó', + '鑺' => ' qú', + '钮' => ' niǔ', + '鑔' => ' chǎ', + '鑞' => ' là', + '鑝' => ' péng', + '鑜' => ' shǎng', + '鑛' => ' kuàng', + '鑚' => ' zuàn', + '鑙' => ' jī', + '鑘' => ' léi', + '鑗' => ' lí', + '鑖' => ' miè', + '鑕' => ' zhì', + '鑓' => ' qian', + '鑠' => ' shuò', + '鑒' => ' jiàn', + '鑑' => ' jiàn', + '鑐' => ' xū', + '鑏' => ' níng', + '鑎' => ' kuì', + '鑍' => ' yīng', + '鑌' => ' bīn', + '鑋' => ' qīng', + '鑊' => ' huò', + '鑉' => ' hé', + '鑟' => ' dú', + '鑡' => ' chuò', + '鑹' => ' cuān', + '鑮' => ' bó', + '鑸' => ' lěi', + '鑷' => ' niè', + '鑶' => ' cáng', + '鑵' => ' guàn', + '鑴' => ' xī', + '鑳' => ' jiàn', + '鑲' => ' xiāng', + '鑱' => ' chán', + '鑰' => ' yào', + '鑯' => ' jiān', + '鑭' => ' làn', + '鑢' => ' lǜ', + '鑬' => ' jiàn', + '鑫' => ' xīn', + '鑪' => ' lú', + '鑩' => ' è', + '鑨' => ' lóng', + '鑧' => ' kuan', + '鑦' => ' xian', + '鑥' => ' lǔ', + '鑤' => ' bào', + '鑣' => ' biāo', + '钭' => ' tǒu', + '钯' => ' bǎ', + '锖' => ' qiāng', + '铱' => ' yī', + '铻' => ' wú', + '铺' => ' pù', + '铹' => ' láo', + '铸' => ' zhù', + '铷' => ' rú', + '银' => ' yín', + '铵' => ' ǎn', + '铴' => ' tāng', + '铳' => ' chòng', + '铲' => ' chǎn', + '铰' => ' jiǎo', + '铽' => ' tè', + '铯' => ' sè', + '铮' => ' zhēng', + '铭' => ' míng', + '铬' => ' gè', + '铫' => ' diào', + '铪' => ' hā', + '铩' => ' shā', + '铨' => ' quán', + '铧' => ' huá', + '铦' => ' xiān', + '铼' => ' lái', + '链' => ' liàn', + '铤' => ' dìng', + '锋' => ' fēng', + '锕' => ' ā', + '锔' => ' jū', + '锓' => ' qǐn', + '锒' => ' láng', + '锑' => ' tī', + '锐' => ' ruì', + '锏' => ' jiǎn', + '锎' => ' kāi', + '锍' => ' liǔ', + '锌' => ' xīn', + '锊' => ' lüè', + '铿' => ' kēng', + '锉' => ' cuò', + '锈' => ' xiù', + '锇' => ' é', + '锆' => ' gào', + '锅' => ' guō', + '锄' => ' chú', + '锃' => ' zèng', + '锂' => ' lǐ', + '锁' => ' suǒ', + '销' => ' xiāo', + '铥' => ' diū', + '铣' => ' xǐ', + '钰' => ' yù', + '钼' => ' mù', + '铆' => ' mǎo', + '铅' => ' qiān', + '铄' => ' shuò', + '铃' => ' líng', + '铂' => ' bó', + '铁' => ' tiě', + '铀' => ' yóu', + '钿' => ' diàn', + '钾' => ' jiǎ', + '钽' => ' tǎn', + '钻' => ' zuān', + '铈' => ' shì', + '钺' => ' yuè', + '钹' => ' bó', + '钸' => ' bù', + '钷' => ' pǒ', + '钶' => ' ē', + '钵' => ' bō', + '钴' => ' gǔ', + '钳' => ' qián', + '钲' => ' zhēng', + '钱' => ' qián', + '铇' => ' bào', + '铉' => ' xuàn', + '铢' => ' zhū', + '铗' => ' jiá', + '铡' => ' zhá', + '铠' => ' kǎi', + '铟' => ' yīn', + '铞' => ' diào', + '铝' => ' lǚ', + '铜' => ' tóng', + '铛' => ' dāng', + '铚' => ' zhì', + '铙' => ' náo', + '铘' => ' yé', + '铖' => ' chéng', + '铊' => ' tā', + '铕' => ' yǒu', + '铔' => ' yà', + '铓' => ' máng', + '铒' => ' ěr', + '铑' => ' lǎo', + '铐' => ' kào', + '铏' => ' xíng', + '铎' => ' duó', + '铍' => ' pī', + '铌' => ' ní', + '铋' => ' bì', + '餦' => ' zhāng', + '館' => ' guǎn', + '銧' => ' guāng', + '鵺' => ' yè', + '鶄' => ' jīng', + '鶃' => ' yì', + '鶂' => ' yì', + '鶁' => ' jīng', + '鶀' => ' qí', + '鵿' => ' shēng', + '鵾' => ' kūn', + '鵽' => ' duò', + '鵼' => ' kōng', + '鵻' => ' zhuī', + '鵹' => ' lí', + '鶆' => ' lái', + '鵸' => ' qí', + '鵷' => ' yuān', + '鵶' => ' yā', + '鵵' => ' tù', + '鵴' => ' jú', + '鵳' => ' jiān', + '鵲' => ' què', + '鵱' => ' lù', + '鵰' => ' diāo', + '鵯' => ' bēi', + '鶅' => ' zī', + '鶇' => ' dōng', + '鵭' => ' qín', + '鶔' => ' róu', + '鶞' => ' chūn', + '鶝' => ' fú', + '鶜' => ' máo', + '鶛' => ' jiē', + '鶚' => ' è', + '鶙' => ' tí', + '鶘' => ' hú', + '鶗' => ' tí', + '鶖' => ' qiū', + '鶕' => ' ān', + '鶓' => ' miáo', + '鶈' => ' qī', + '鶒' => ' chì', + '鶑' => ' yīng', + '鶐' => ' shù', + '鶏' => ' jī', + '鶎' => ' zun', + '鶍' => ' yi', + '鶌' => ' jué', + '鶋' => ' jū', + '鶊' => ' gēng', + '鶉' => ' chún', + '鵮' => ' qiān', + '鵬' => ' péng', + '鶠' => ' yǎn', + '鵆' => ' heng', + '鵐' => ' wú', + '鵏' => ' bǔ', + '鵎' => ' tuǒ', + '鵍' => ' huān', + '鵌' => ' tú', + '鵋' => ' jì', + '鵊' => ' jiá', + '鵉' => ' luán', + '鵈' => ' e', + '鵇' => ' nian', + '鵅' => ' luò', + '鵒' => ' yù', + '鵄' => ' zhī', + '鵃' => ' zhōu', + '鵂' => ' xiū', + '鵁' => ' jiāo', + '鵀' => ' rén', + '鴿' => ' gē', + '鴾' => ' móu', + '鴽' => ' rú', + '鴼' => ' luò', + '鴻' => ' hóng', + '鵑' => ' juān', + '鵓' => ' bó', + '鵫' => ' zhuó', + '鵠' => ' hú', + '鵪' => ' ān', + '鵩' => ' fú', + '鵨' => ' shū', + '鵧' => ' pí', + '鵦' => ' lù', + '鵥' => ' pan', + '鵤' => ' jiao', + '鵣' => ' lài', + '鵢' => ' shēn', + '鵡' => ' wǔ', + '鵟' => ' kuáng', + '鵔' => ' jùn', + '鵞' => ' é', + '鵝' => ' é', + '鵜' => ' tí', + '鵛' => ' jīng', + '鵚' => ' tū', + '鵙' => ' jú', + '鵘' => ' jùn', + '鵗' => ' xī', + '鵖' => ' bī', + '鵕' => ' xùn', + '鶟' => ' tú', + '鶡' => ' hé', + '鴹' => ' yáng', + '鷢' => ' jué', + '鷬' => ' huáng', + '鷫' => ' sù', + '鷪' => ' yīng', + '鷩' => ' bì', + '鷨' => ' huá', + '鷧' => ' yì', + '鷦' => ' jiāo', + '鷥' => ' sī', + '鷤' => ' tí', + '鷣' => ' yín', + '鷡' => ' wú', + '鷮' => ' jiāo', + '鷠' => ' yú', + '鷟' => ' zhuó', + '鷞' => ' shuāng', + '鷝' => ' bì', + '鷜' => ' lǘ', + '鷛' => ' yōng', + '鷚' => ' liù', + '鷙' => ' zhì', + '鷘' => ' chì', + '鷗' => ' ōu', + '鷭' => ' fán', + '鷯' => ' liáo', + '鷕' => ' yǎo', + '鷼' => ' xián', + '鸆' => ' yú', + '鸅' => ' zé', + '鸄' => ' jī', + '鸃' => ' yí', + '鸂' => ' xī', + '鸁' => ' luó', + '鸀' => ' chǔ', + '鷿' => ' pì', + '鷾' => ' yì', + '鷽' => ' xué', + '鷻' => ' tuán', + '鷰' => ' yàn', + '鷺' => ' lù', + '鷹' => ' yīng', + '鷸' => ' yù', + '鷷' => ' zūn', + '鷶' => ' mǎi', + '鷵' => ' tú', + '鷴' => ' xián', + '鷳' => ' xián', + '鷲' => ' jiù', + '鷱' => ' gāo', + '鷖' => ' yī', + '鷔' => ' áo', + '鶢' => ' yuán', + '鶮' => ' hè', + '鶸' => ' ruò', + '鶷' => ' xiá', + '鶶' => ' táng', + '鶵' => ' chú', + '鶴' => ' hè', + '鶳' => ' shī', + '鶲' => ' wēng', + '鶱' => ' xiān', + '鶰' => ' yuán', + '鶯' => ' yīng', + '鶭' => ' fǎng', + '鶺' => ' jí', + '鶬' => ' cāng', + '鶫' => ' dong', + '鶪' => ' jú', + '鶩' => ' wù', + '鶨' => ' chuàn', + '鶧' => ' yīng', + '鶦' => ' hú', + '鶥' => ' méi', + '鶤' => ' kūn', + '鶣' => ' piān', + '鶹' => ' liú', + '鶻' => ' gú', + '鷓' => ' zhè', + '鷈' => ' tī', + '鷒' => ' tuán', + '鷑' => ' jí', + '鷐' => ' chén', + '鷏' => ' tián', + '鷎' => ' gāo', + '鷍' => ' jiāo', + '鷌' => ' mǎ', + '鷋' => ' tú', + '鷊' => ' yì', + '鷉' => ' tī', + '鷇' => ' kòu', + '鶼' => ' jiān', + '鷆' => ' tián', + '鷅' => ' lì', + '鷄' => ' jī', + '鷃' => ' yàn', + '鷂' => ' yào', + '鷁' => ' yì', + '鷀' => ' cí', + '鶿' => ' cí', + '鶾' => ' hàn', + '鶽' => ' sǔn', + '鴺' => ' tí', + '鴸' => ' zhū', + '鸈' => ' yè', + '鲪' => ' jūn', + '鲴' => ' gù', + '鲳' => ' chāng', + '鲲' => ' kūn', + '鲱' => ' fēi', + '鲰' => ' zōu', + '鲯' => ' qí', + '鲮' => ' líng', + '鲭' => ' qīng', + '鲬' => ' yǒng', + '鲫' => ' jì', + '鲩' => ' huàn', + '鲶' => ' nián', + '鲨' => ' shā', + '鲧' => ' gǔn', + '鲦' => ' tiáo', + '鲥' => ' shí', + '鲤' => ' lǐ', + '鲣' => ' jiān', + '鲢' => ' lián', + '鲡' => ' lí', + '鲠' => ' gěng', + '鲟' => ' xún', + '鲵' => ' ní', + '鲷' => ' diāo', + '鲝' => ' zhǎ', + '鳄' => ' è', + '鳎' => ' tǎ', + '鳍' => ' qí', + '鳌' => ' áo', + '鳋' => ' sāo', + '鳊' => ' biān', + '鳉' => ' jiāng', + '鳈' => ' quán', + '鳇' => ' huáng', + '鳆' => ' fù', + '鳅' => ' qiū', + '鳃' => ' sāi', + '鲸' => ' jīng', + '鳂' => ' wēi', + '鳁' => ' wēn', + '鳀' => ' tí', + '鲿' => ' cháng', + '鲾' => ' bī', + '鲽' => ' dié', + '鲼' => ' fèn', + '鲻' => ' zī', + '鲺' => ' shī', + '鲹' => ' shēn', + '鲞' => ' xiǎng', + '鲜' => ' xiān', + '鳐' => ' yáo', + '鱶' => ' xiǎng', + '鲀' => ' tún', + '鱿' => ' yóu', + '鱾' => ' jǐ', + '鱽' => ' dāo', + '鱼' => ' yú', + '鱻' => ' xiān', + '鱺' => ' lí', + '鱹' => ' guàn', + '鱸' => ' lú', + '鱷' => ' è', + '鱵' => ' zhēn', + '鲂' => ' fáng', + '鱴' => ' miè', + '鱳' => ' lì', + '鱲' => ' liè', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/data/words_3 b/lib/vendor/overtrue/pinyin/data/words_3 new file mode 100644 index 0000000000..008d629b69 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_3 @@ -0,0 +1,8003 @@ + ' lì', + '鱰' => ' shu', + '鱯' => ' hù', + '鱮' => ' xù', + '鱭' => ' jì', + '鱬' => ' rú', + '鱫' => ' ai', + '鲁' => ' lǔ', + '鲃' => ' bā', + '鲛' => ' jiāo', + '鲐' => ' tái', + '鲚' => ' jì', + '鲙' => ' kuài', + '鲘' => ' hòu', + '鲗' => ' zéi', + '鲖' => ' tóng', + '鲕' => ' ér', + '鲔' => ' wěi', + '鲓' => ' kǎo', + '鲒' => ' jié', + '鲑' => ' guī', + '鲏' => ' pí', + '鲄' => ' hé', + '鲎' => ' hòu', + '鲍' => ' bào', + '鲌' => ' bà', + '鲋' => ' fù', + '鲊' => ' zhǎ', + '鲉' => ' yóu', + '鲈' => ' lú', + '鲇' => ' nián', + '鲆' => ' píng', + '鲅' => ' bà', + '鳏' => ' guān', + '鳑' => ' páng', + '鴷' => ' liè', + '鴒' => ' líng', + '鴜' => ' cí', + '鴛' => ' yuān', + '鴚' => ' gē', + '鴙' => ' zhì', + '鴘' => ' biǎn', + '鴗' => ' lì', + '鴖' => ' mín', + '鴕' => ' tuó', + '鴔' => ' fú', + '鴓' => ' miè', + '鴑' => ' rú', + '鴞' => ' xiāo', + '鴐' => ' gē', + '鴏' => ' dài', + '鴎' => ' ōu', + '鴍' => ' wén', + '鴌' => ' fèng', + '鴋' => ' fāng', + '鴊' => ' zhèng', + '鴉' => ' yā', + '鴈' => ' yàn', + '鴇' => ' bǎo', + '鴝' => ' qú', + '鴟' => ' chī', + '鴅' => ' huān', + '鴬' => ' yīng', + '鴶' => ' jiá', + '鴵' => ' xiāo', + '鴴' => ' héng', + '鴳' => ' yàn', + '鴲' => ' zhī', + '鴱' => ' ài', + '鴰' => ' guā', + '鴯' => ' ér', + '鴮' => ' wū', + '鴭' => ' duī', + '鴫' => ' tian', + '鴠' => ' dàn', + '鴪' => ' yù', + '鴩' => ' tiě', + '鴨' => ' yā', + '鴧' => ' ròng', + '鴦' => ' yāng', + '鴥' => ' yù', + '鴤' => ' dōng', + '鴣' => ' gū', + '鴢' => ' yǎo', + '鴡' => ' jū', + '鴆' => ' zhèn', + '鴄' => ' pǐ', + '鳒' => ' jiān', + '鳞' => ' lín', + '鳨' => ' lì', + '鳧' => ' fú', + '鳦' => ' yǐ', + '鳥' => ' niǎo', + '鳤' => ' guǎn', + '鳣' => ' zhān', + '鳢' => ' lǐ', + '鳡' => ' gǎn', + '鳠' => ' hù', + '鳟' => ' zūn', + '鳝' => ' shàn', + '鳪' => ' bú', + '鳜' => ' guì', + '鳛' => ' xí', + '鳚' => ' wèi', + '鳙' => ' yōng', + '鳘' => ' mǐn', + '鳗' => ' mán', + '鳖' => ' biē', + '鳕' => ' xuě', + '鳔' => ' biào', + '鳓' => ' lè', + '鳩' => ' jiū', + '鳫' => ' yàn', + '鴃' => ' jué', + '鳸' => ' hù', + '鴂' => ' jué', + '鴁' => ' yāo', + '鴀' => ' fǒu', + '鳿' => ' yù', + '鳾' => ' shī', + '鳽' => ' jiān', + '鳼' => ' wén', + '鳻' => ' bān', + '鳺' => ' fū', + '鳹' => ' qín', + '鳷' => ' zhī', + '鳬' => ' fǔ', + '鳶' => ' yuān', + '鳵' => ' bǎo', + '鳴' => ' míng', + '鳳' => ' fèng', + '鳲' => ' shī', + '鳱' => ' gān', + '鳰' => ' ru', + '鳯' => ' fèng', + '鳮' => ' jī', + '鳭' => ' diāo', + '鸇' => ' zhān', + '鸉' => ' yáng', + '鱩' => ' lei', + '鼚' => ' chāng', + '鼤' => ' wén', + '鼣' => ' fèi', + '鼢' => ' fén', + '鼡' => ' shǔ', + '鼠' => ' shǔ', + '鼟' => ' tēng', + '鼞' => ' tāng', + '鼝' => ' yuān', + '鼜' => ' qì', + '鼛' => ' gāo', + '鼙' => ' pí', + '鼦' => ' diāo', + '鼘' => ' yuān', + '鼗' => ' táo', + '鼖' => ' fén', + '鼕' => ' dōng', + '鼔' => ' gǔ', + '鼓' => ' gǔ', + '鼒' => ' zī', + '鼑' => ' dǐng', + '鼐' => ' nài', + '鼏' => ' mì', + '鼥' => ' bá', + '鼧' => ' tuó', + '鼍' => ' tuó', + '鼴' => ' yǎn', + '鼾' => ' hān', + '鼽' => ' qiú', + '鼼' => ' yǎo', + '鼻' => ' bí', + '鼺' => ' léi', + '鼹' => ' yǎn', + '鼸' => ' xiàn', + '鼷' => ' xī', + '鼶' => ' sī', + '鼵' => ' tū', + '鼳' => ' jú', + '鼨' => ' zhōng', + '鼲' => ' hún', + '鼱' => ' jīng', + '鼰' => ' niàn', + '鼯' => ' wú', + '鼮' => ' tíng', + '鼭' => ' shí', + '鼬' => ' yòu', + '鼫' => ' shí', + '鼪' => ' shēng', + '鼩' => ' qú', + '鼎' => ' dǐng', + '鼌' => ' cháo', + '齀' => ' wù', + '黦' => ' yuè', + '黰' => ' zhěn', + '黯' => ' àn', + '黮' => ' dǎn', + '黭' => ' yǎn', + '黬' => ' yán', + '黫' => ' yān', + '黪' => ' cǎn', + '黩' => ' dú', + '黨' => ' dǎng', + '黧' => ' lí', + '黥' => ' qíng', + '黲' => ' cǎn', + '黤' => ' yǎn', + '黣' => ' měi', + '黢' => ' qū', + '黡' => ' yǎn', + '黠' => ' xiá', + '黟' => ' yī', + '點' => ' diǎn', + '黝' => ' yǒu', + '黜' => ' chù', + '黛' => ' dài', + '黱' => ' dài', + '黳' => ' yī', + '鼋' => ' yuán', + '鼀' => ' cù', + '鼊' => ' bì', + '鼉' => ' tuó', + '鼈' => ' biē', + '鼇' => ' áo', + '鼆' => ' méng', + '鼅' => ' zhī', + '鼄' => ' zhū', + '鼃' => ' wā', + '鼂' => ' cháo', + '鼁' => ' qù', + '黿' => ' yuán', + '黴' => ' méi', + '黾' => ' miǎn', + '黽' => ' miǎn', + '黼' => ' fǔ', + '黻' => ' fú', + '黺' => ' fěn', + '黹' => ' zhǐ', + '黸' => ' lú', + '黷' => ' dú', + '黶' => ' yǎn', + '黵' => ' zhǎn', + '鼿' => ' wù', + '齁' => ' hōu', + '黙' => ' mò', + '龂' => ' yín', + '龌' => ' wò', + '龋' => ' qǔ', + '龊' => ' chuò', + '龉' => ' yǔ', + '龈' => ' kěn', + '龇' => ' zī', + '龆' => ' tiáo', + '龅' => ' bāo', + '龄' => ' líng', + '龃' => ' jǔ', + '龁' => ' hé', + '龎' => ' páng', + '龀' => ' chèn', + '齿' => ' chǐ', + '齾' => ' yà', + '齽' => ' jìn', + '齼' => ' chǔ', + '齻' => ' diān', + '齺' => ' zōu', + '齹' => ' cī', + '齸' => ' yì', + '齷' => ' wò', + '龍' => ' lóng', + '龏' => ' gōng', + '齵' => ' óu', + '龜' => ' guī', + '鿃' => ' shǎn', + '龥' => ' yù', + '龤' => ' xié', + '龣' => ' jué', + '龢' => ' hé', + '龡' => ' chuì', + '龠' => ' yuè', + '龟' => ' guī', + '龞' => ' biē', + '龝' => ' qiū', + '龛' => ' kān', + '龐' => ' páng', + '龚' => ' gōng', + '龙' => ' lóng', + '龘' => ' dá', + '龗' => ' líng', + '龖' => ' dá', + '龕' => ' kān', + '龔' => ' gōng', + '龓' => ' lǒng', + '龒' => ' lóng', + '龑' => ' yǎn', + '齶' => ' è', + '齴' => ' yǎn', + '齂' => ' xiè', + '齎' => ' jī', + '齘' => ' xiè', + '齗' => ' yín', + '齖' => ' yá', + '齕' => ' hé', + '齔' => ' chèn', + '齓' => ' chèn', + '齒' => ' chǐ', + '齑' => ' jī', + '齐' => ' qí', + '齏' => ' jī', + '齍' => ' zī', + '齚' => ' zé', + '齌' => ' jì', + '齋' => ' zhāi', + '齊' => ' qí', + '齉' => ' nàng', + '齈' => ' nòng', + '齇' => ' zhā', + '齆' => ' wèng', + '齅' => ' xiù', + '齄' => ' zhā', + '齃' => ' è', + '齙' => ' bāo', + '齛' => ' xiè', + '齳' => ' yǔn', + '齨' => ' jiù', + '齲' => ' qǔ', + '齱' => ' zōu', + '齰' => ' zé', + '齯' => ' ní', + '齮' => ' yǐ', + '齭' => ' chǔ', + '齬' => ' yǔ', + '齫' => ' kǔn', + '齪' => ' chuò', + '齩' => ' yǎo', + '齧' => ' niè', + '齜' => ' chái', + '齦' => ' kěn', + '齥' => ' xiè', + '齤' => ' quán', + '齣' => ' chū', + '齢' => ' líng', + '齡' => ' líng', + '齠' => ' tiáo', + '齟' => ' jǔ', + '齞' => ' yǎn', + '齝' => ' chī', + '黚' => ' qián', + '默' => ' mò', + '鸊' => ' pì', + '鹊' => ' què', + '鹔' => ' sù', + '鹓' => ' yuān', + '鹒' => ' gēng', + '鹑' => ' chún', + '鹐' => ' qiān', + '鹏' => ' péng', + '鹎' => ' bēi', + '鹍' => ' kūn', + '鹌' => ' ān', + '鹋' => ' miáo', + '鹉' => ' wǔ', + '鹖' => ' hé', + '鹈' => ' tí', + '鹇' => ' xián', + '鹆' => ' yù', + '鹅' => ' é', + '鹄' => ' gǔ', + '鹃' => ' juān', + '鹂' => ' lí', + '鹁' => ' bó', + '鹀' => ' wú', + '鸿' => ' hóng', + '鹕' => ' hú', + '鹗' => ' è', + '鸽' => ' gē', + '鹤' => ' hè', + '鹮' => ' huán', + '鹭' => ' lù', + '鹬' => ' yù', + '鹫' => ' jiù', + '鹪' => ' jiāo', + '鹩' => ' liáo', + '鹨' => ' liù', + '鹧' => ' zhè', + '鹦' => ' yīng', + '鹥' => ' yī', + '鹣' => ' jiān', + '鹘' => ' gǔ', + '鹢' => ' yì', + '鹡' => ' jí', + '鹠' => ' liú', + '鹟' => ' wēng', + '鹞' => ' yào', + '鹝' => ' yì', + '鹜' => ' wù', + '鹛' => ' méi', + '鹚' => ' cí', + '鹙' => ' qiū', + '鸾' => ' luán', + '鸼' => ' zhōu', + '鹰' => ' yīng', + '鸖' => ' hè', + '鸠' => ' jiū', + '鸟' => ' niǎo', + '鸞' => ' luán', + '鸝' => ' lí', + '鸜' => ' qú', + '鸛' => ' guàn', + '鸚' => ' yīng', + '鸙' => ' yuè', + '鸘' => ' shuāng', + '鸗' => ' lóng', + '鸕' => ' lú', + '鸢' => ' yuān', + '鸔' => ' bào', + '鸓' => ' lěi', + '鸒' => ' yù', + '鸑' => ' yuè', + '鸐' => ' dí', + '鸏' => ' méng', + '鸎' => ' yīng', + '鸍' => ' mí', + '鸌' => ' hù', + '鸋' => ' níng', + '鸡' => ' jī', + '鸣' => ' míng', + '鸻' => ' héng', + '鸰' => ' líng', + '鸺' => ' xiū', + '鸹' => ' guā', + '鸸' => ' ér', + '鸷' => ' zhì', + '鸶' => ' sī', + '鸵' => ' tuó', + '鸴' => ' xué', + '鸳' => ' yuān', + '鸲' => ' qú', + '鸱' => ' chī', + '鸯' => ' yāng', + '鸤' => ' shī', + '鸮' => ' xiāo', + '鸭' => ' yā', + '鸬' => ' lú', + '鸫' => ' dōng', + '鸪' => ' gū', + '鸩' => ' zhèn', + '鸨' => ' bǎo', + '鸧' => ' cāng', + '鸦' => ' yā', + '鸥' => ' ōu', + '鹯' => ' zhān', + '鹱' => ' hù', + '黗' => ' tūn', + '麲' => ' xiàn', + '麼' => ' me', + '麻' => ' má', + '麺' => ' miàn', + '麹' => ' qū', + '麸' => ' fū', + '麷' => ' fēng', + '麶' => ' chi', + '麵' => ' miàn', + '麴' => ' qū', + '麳' => ' lái', + '麱' => ' fū', + '麾' => ' huī', + '麰' => ' móu', + '麯' => ' qū', + '麮' => ' qù', + '麭' => ' pào', + '麬' => ' fū', + '麫' => ' miǎn', + '麪' => ' miàn', + '麩' => ' fū', + '麨' => ' chǎo', + '麧' => ' hé', + '麽' => ' mó', + '麿' => ' mo', + '麥' => ' mài', + '黌' => ' hóng', + '黖' => ' xì', + '黕' => ' dǎn', + '黔' => ' qián', + '黓' => ' yì', + '黒' => ' hēi', + '黑' => ' hēi', + '黐' => ' chī', + '黏' => ' nián', + '黎' => ' lí', + '黍' => ' shǔ', + '黋' => ' kuàng', + '黀' => ' zōu', + '黊' => ' huà', + '黉' => ' hóng', + '黈' => ' tǒu', + '黇' => ' tiān', + '黆' => ' guāng', + '黅' => ' jīn', + '黄' => ' huáng', + '黃' => ' huáng', + '黂' => ' fén', + '黁' => ' nún', + '麦' => ' mài', + '麤' => ' cū', + '鹲' => ' méng', + '鹾' => ' cuó', + '麈' => ' zhǔ', + '麇' => ' jūn', + '麆' => ' zhù', + '麅' => ' páo', + '麄' => ' cū', + '麃' => ' páo', + '麂' => ' jǐ', + '麁' => ' cū', + '麀' => ' yōu', + '鹿' => ' lù', + '鹽' => ' yán', + '麊' => ' mí', + '鹼' => ' jiǎn', + '鹻' => ' jiǎn', + '鹺' => ' cuó', + '鹹' => ' xián', + '鹸' => ' jiǎn', + '鹷' => ' líng', + '鹶' => ' jīn', + '鹵' => ' lǔ', + '鹴' => ' shuāng', + '鹳' => ' guàn', + '麉' => ' jiān', + '麋' => ' mí', + '麣' => ' yán', + '麘' => ' xiāng', + '麢' => ' líng', + '麡' => ' qí', + '麠' => ' jīng', + '麟' => ' lín', + '麞' => ' zhāng', + '麝' => ' shè', + '麜' => ' lì', + '麛' => ' mí', + '麚' => ' jiā', + '麙' => ' xián', + '麗' => ' lì', + '麌' => ' yǔ', + '麖' => ' jīng', + '麕' => ' jūn', + '麔' => ' jiù', + '麓' => ' lù', + '麒' => ' qí', + '麑' => ' ní', + '麐' => ' lín', + '麏' => ' jūn', + '麎' => ' chén', + '麍' => ' liú', + '鱪' => ' shu', + '鱨' => ' cháng', + '餩' => ' è', + '騹' => ' lí', + '驃' => ' biāo', + '驂' => ' cān', + '驁' => ' ào', + '驀' => ' mò', + '騿' => ' zhāng', + '騾' => ' luó', + '騽' => ' xí', + '騼' => ' lù', + '騻' => ' shuāng', + '騺' => ' zhì', + '騸' => ' shàn', + '驅' => ' qū', + '騷' => ' sāo', + '騶' => ' zōu', + '騵' => ' yuán', + '騴' => ' yàn', + '騳' => ' dú', + '騲' => ' cǎo', + '騱' => ' xí', + '騰' => ' téng', + '騯' => ' péng', + '騮' => ' liú', + '驄' => ' cōng', + '驆' => ' bì', + '騬' => ' chéng', + '驓' => ' céng', + '驝' => ' tuō', + '驜' => ' yè', + '驛' => ' yì', + '驚' => ' jīng', + '驙' => ' zhān', + '驘' => ' luó', + '驗' => ' yàn', + '驖' => ' tiě', + '驕' => ' jiāo', + '驔' => ' diàn', + '驒' => ' tuó', + '驇' => ' zhì', + '驑' => ' liú', + '驐' => ' dūn', + '驏' => ' zhàn', + '驎' => ' lín', + '驍' => ' xiāo', + '驌' => ' sù', + '驋' => ' bō', + '驊' => ' huá', + '驉' => ' xū', + '驈' => ' yù', + '騭' => ' zhì', + '騫' => ' qiān', + '驟' => ' zhòu', + '騅' => ' zhuī', + '騏' => ' qí', + '騎' => ' qí', + '騍' => ' kè', + '騌' => ' zōng', + '騋' => ' lái', + '騊' => ' táo', + '騉' => ' kūn', + '騈' => ' pián', + '騇' => ' shè', + '騆' => ' zhōu', + '騄' => ' lù', + '騑' => ' fēi', + '騃' => ' ái', + '騂' => ' xīng', + '騁' => ' chěng', + '騀' => ' ě', + '駿' => ' jùn', + '駾' => ' tuì', + '駽' => ' xuān', + '駼' => ' tú', + '駻' => ' hàn', + '駺' => ' láng', + '騐' => ' yàn', + '騒' => ' sāo', + '騪' => ' sōu', + '騟' => ' yú', + '騩' => ' guī', + '騨' => ' tuó', + '騧' => ' guā', + '騦' => ' sī', + '騥' => ' róu', + '騤' => ' kuí', + '騣' => ' zōng', + '騢' => ' xiá', + '騡' => ' quán', + '騠' => ' tí', + '騞' => ' huō', + '験' => ' yǎn', + '騝' => ' qián', + '騜' => ' huáng', + '騛' => ' fēi', + '騚' => ' qián', + '騙' => ' piàn', + '騘' => ' cōng', + '騗' => ' piàn', + '騖' => ' wù', + '騕' => ' yǎo', + '騔' => ' gé', + '驞' => ' pīn', + '驠' => ' yàn', + '駸' => ' qīn', + '骡' => ' luó', + '骫' => ' wěi', + '骪' => ' wěi', + '骩' => ' wěi', + '骨' => ' gǔ', + '骧' => ' xiāng', + '骦' => ' shuāng', + '骥' => ' jì', + '骤' => ' zhòu', + '骣' => ' chǎn', + '骢' => ' cōng', + '骠' => ' biāo', + '骭' => ' gàn', + '骟' => ' shàn', + '骞' => ' qiān', + '骝' => ' liú', + '骜' => ' ào', + '骛' => ' wù', + '骚' => ' sāo', + '骙' => ' kuí', + '骘' => ' zhì', + '骗' => ' piàn', + '骖' => ' cān', + '骬' => ' yú', + '骮' => ' yì', + '骔' => ' zōng', + '骻' => ' kuà', + '髅' => ' lóu', + '髄' => ' suǐ', + '髃' => ' yú', + '髂' => ' qià', + '髁' => ' kē', + '髀' => ' bì', + '骿' => ' pián', + '骾' => ' gěng', + '骽' => ' tuǐ', + '骼' => ' gé', + '骺' => ' hóu', + '骯' => ' āng', + '骹' => ' qiāo', + '骸' => ' hái', + '骷' => ' kū', + '骶' => ' dǐ', + '骵' => ' tǐ', + '骴' => ' cī', + '骳' => ' bèi', + '骲' => ' bào', + '骱' => ' jiè', + '骰' => ' tóu', + '骕' => ' sù', + '骓' => ' zhuī', + '驡' => ' lóng', + '驭' => ' yù', + '驷' => ' sì', + '驶' => ' shǐ', + '驵' => ' zǎng', + '驴' => ' lǘ', + '驳' => ' bó', + '驲' => ' rì', + '驱' => ' qū', + '驰' => ' chí', + '驯' => ' xún', + '驮' => ' tuó', + '马' => ' mǎ', + '驹' => ' jū', + '驫' => ' biāo', + '驪' => ' lí', + '驩' => ' huān', + '驨' => ' xí', + '驧' => ' jú', + '驦' => ' shuāng', + '驥' => ' jì', + '驤' => ' xiāng', + '驣' => ' téng', + '驢' => ' lǘ', + '驸' => ' fù', + '驺' => ' zōu', + '骒' => ' kè', + '骇' => ' hài', + '骑' => ' qí', + '骐' => ' qí', + '骏' => ' jùn', + '骎' => ' qīn', + '骍' => ' xīng', + '验' => ' yàn', + '骋' => ' chěng', + '骊' => ' lí', + '骉' => ' biāo', + '骈' => ' pián', + '骆' => ' luò', + '驻' => ' zhù', + '骅' => ' huá', + '骄' => ' jiāo', + '骃' => ' yīn', + '骂' => ' mà', + '骁' => ' xiāo', + '骀' => ' dài', + '驿' => ' yì', + '驾' => ' jià', + '驽' => ' nú', + '驼' => ' tuó', + '駹' => ' máng', + '駷' => ' sǒng', + '髇' => ' xiāo', + '饩' => ' xì', + '饳' => ' duò', + '饲' => ' sì', + '饱' => ' bǎo', + '饰' => ' shì', + '饯' => ' jiàn', + '饮' => ' yǐn', + '饭' => ' fàn', + '饬' => ' chì', + '饫' => ' yù', + '饪' => ' rèn', + '饨' => ' tún', + '饵' => ' ěr', + '饧' => ' táng', + '饦' => ' tuō', + '饥' => ' jī', + '饤' => ' dìng', + '饣' => ' shí', + '饢' => ' náng', + '饡' => ' zàn', + '饠' => ' luó', + '饟' => ' xiǎng', + '饞' => ' chán', + '饴' => ' yí', + '饶' => ' ráo', + '饜' => ' yàn', + '馃' => ' guǒ', + '馍' => ' mó', + '馌' => ' yè', + '馋' => ' chán', + '馊' => ' sōu', + '馉' => ' gǔ', + '馈' => ' kuì', + '馇' => ' chā', + '馆' => ' guǎn', + '馅' => ' xiàn', + '馄' => ' hún', + '馂' => ' jùn', + '饷' => ' xiǎng', + '馁' => ' něi', + '馀' => ' yú', + '饿' => ' è', + '饾' => ' dòu', + '饽' => ' bō', + '饼' => ' bǐng', + '饻' => ' xī', + '饺' => ' jiǎo', + '饹' => ' le', + '饸' => ' hé', + '饝' => ' mó', + '饛' => ' méng', + '馏' => ' liú', + '餵' => ' wèi', + '餿' => ' sōu', + '餾' => ' liù', + '餽' => ' kuì', + '餼' => ' xì', + '餻' => ' gāo', + '餺' => ' bó', + '餹' => ' táng', + '餸' => ' sòng', + '餷' => ' chā', + '餶' => ' gǔ', + '餴' => ' fēn', + '饁' => ' yè', + '餳' => ' táng', + '餲' => ' ài', + '餱' => ' hóu', + '餰' => ' jiān', + '餯' => ' huì', + '餮' => ' tiè', + '餭' => ' huáng', + '餬' => ' hú', + '餫' => ' yùn', + '餪' => ' nuǎn', + '饀' => ' táo', + '饂' => ' yún', + '饚' => ' hài', + '饏' => ' dàn', + '饙' => ' fēn', + '饘' => ' zhān', + '饗' => ' xiǎng', + '饖' => ' wèi', + '饕' => ' tāo', + '饔' => ' yōng', + '饓' => ' chēng', + '饒' => ' ráo', + '饑' => ' jī', + '饐' => ' yì', + '饎' => ' chì', + '饃' => ' mó', + '饍' => ' shàn', + '饌' => ' zhuàn', + '饋' => ' kuì', + '饊' => ' sǎn', + '饉' => ' jǐn', + '饈' => ' xiū', + '饇' => ' yù', + '饆' => ' bì', + '饅' => ' mán', + '饄' => ' táng', + '馎' => ' bó', + '馐' => ' xiū', + '駶' => ' jú', + '駑' => ' nú', + '駛' => ' shǐ', + '駚' => ' yǎng', + '駙' => ' fù', + '駘' => ' tái', + '駗' => ' zhěn', + '駖' => ' líng', + '駕' => ' jià', + '駔' => ' zǎng', + '駓' => ' pī', + '駒' => ' jū', + '駐' => ' zhù', + '駝' => ' tuó', + '駏' => ' jù', + '駎' => ' zhòu', + '駍' => ' péi', + '駌' => ' yuān', + '駋' => ' zhāo', + '駊' => ' pǒ', + '駉' => ' jiōng', + '駈' => ' qū', + '駇' => ' wén', + '駆' => ' qū', + '駜' => ' bì', + '駞' => ' tuó', + '駄' => ' tuó', + '駫' => ' jiōng', + '駵' => ' liú', + '駴' => ' xiè', + '駳' => ' dàn', + '駲' => ' zhou', + '駱' => ' luò', + '駰' => ' yīn', + '駯' => ' zhū', + '駮' => ' bó', + '駭' => ' hài', + '駬' => ' ěr', + '駪' => ' shēn', + '駟' => ' sì', + '駩' => ' quān', + '駨' => ' xūn', + '駧' => ' dòng', + '駦' => ' téng', + '駥' => ' róng', + '駤' => ' zhì', + '駣' => ' táo', + '駢' => ' pián', + '駡' => ' mà', + '駠' => ' liú', + '駅' => ' yì', + '駃' => ' jué', + '馑' => ' jǐn', + '馝' => ' bì', + '馧' => ' yūn', + '馦' => ' xiān', + '馥' => ' fù', + '馤' => ' ài', + '馣' => ' ān', + '馢' => ' jiān', + '馡' => ' fēi', + '馠' => ' hān', + '馟' => ' tú', + '馞' => ' bó', + '馜' => ' nǐ', + '馩' => ' fén', + '馛' => ' bó', + '馚' => ' fén', + '香' => ' xiāng', + '馘' => ' guó', + '馗' => ' kuí', + '首' => ' shǒu', + '馕' => ' náng', + '馔' => ' zhuàn', + '馓' => ' sǎn', + '馒' => ' mán', + '馨' => ' xīn', + '馪' => ' pīn', + '駂' => ' bǎo', + '馷' => ' pèi', + '駁' => ' bó', + '駀' => ' yóu', + '馿' => ' lǘ', + '馾' => ' dàn', + '馽' => ' zhí', + '馼' => ' wén', + '馻' => ' yǔn', + '馺' => ' sà', + '馹' => ' rì', + '馸' => ' xìn', + '馶' => ' zhī', + '馫' => ' xīn', + '馵' => ' zhù', + '馴' => ' xún', + '馳' => ' chí', + '馲' => ' zhé', + '馱' => ' tuó', + '馰' => ' dí', + '馯' => ' hàn', + '馮' => ' féng', + '馭' => ' yù', + '馬' => ' mǎ', + '髆' => ' bó', + '髈' => ' bǎng', + '鱧' => ' lǐ', + '鯚' => ' jì', + '鯤' => ' kūn', + '鯣' => ' yì', + '鯢' => ' ní', + '鯡' => ' fèi', + '鯠' => ' lái', + '鯟' => ' dōng', + '鯞' => ' zhǒu', + '鯝' => ' gù', + '鯜' => ' qiè', + '鯛' => ' diāo', + '鯙' => ' chún', + '鯦' => ' jiù', + '鯘' => ' něi', + '鯗' => ' xiǎng', + '鯖' => ' zhēng', + '鯕' => ' qí', + '鯔' => ' zī', + '鯓' => ' ní', + '鯒' => ' yǒng', + '鯑' => ' xi', + '鯐' => ' zou', + '鯏' => ' li', + '鯥' => ' lù', + '鯧' => ' chāng', + '鯍' => ' méng', + '鯴' => ' shī', + '鯾' => ' biān', + '鯽' => ' zéi', + '鯼' => ' zōng', + '鯻' => ' là', + '鯺' => ' zhū', + '鯹' => ' xīng', + '鯸' => ' hóu', + '鯷' => ' tí', + '鯶' => ' hǔn', + '鯵' => ' shēn', + '鯳' => ' di', + '鯨' => ' jīng', + '鯲' => ' yu', + '鯱' => ' hu', + '鯰' => ' nián', + '鯯' => ' zhì', + '鯮' => ' zōng', + '鯭' => ' měng', + '鯬' => ' lí', + '鯫' => ' zōu', + '鯪' => ' líng', + '鯩' => ' lún', + '鯎' => ' cheng', + '鯌' => ' kào', + '鰀' => ' huàn', + '鮦' => ' tóng', + '鮰' => ' huí', + '鮯' => ' gé', + '鮮' => ' xiān', + '鮭' => ' guī', + '鮬' => ' kū', + '鮫' => ' jiāo', + '鮪' => ' wěi', + '鮩' => ' bìng', + '鮨' => ' yì', + '鮧' => ' tǐ', + '鮥' => ' luò', + '鮲' => ' fu', + '鮤' => ' liè', + '鮣' => ' yìn', + '鮢' => ' zhū', + '鮡' => ' zhào', + '鮠' => ' wéi', + '鮟' => ' àn', + '鮞' => ' ér', + '鮝' => ' xiǎng', + '鮜' => ' hòu', + '鮛' => ' shū', + '鮱' => ' lao', + '鮳' => ' kào', + '鯋' => ' shā', + '鯀' => ' gǔn', + '鯊' => ' shā', + '鯉' => ' lǐ', + '鯈' => ' tiáo', + '鯇' => ' huàn', + '鯆' => ' pū', + '鯅' => ' shān', + '鯄' => ' qiú', + '鯃' => ' wú', + '鯂' => ' su', + '鯁' => ' gěng', + '鮿' => ' zhé', + '鮴' => ' xiu', + '鮾' => ' něi', + '鮽' => ' yú', + '鮼' => ' qīn', + '鮻' => ' suō', + '鮺' => ' zhǎ', + '鮹' => ' shāo', + '鮸' => ' miǎn', + '鮷' => ' tí', + '鮶' => ' jūn', + '鮵' => ' duó', + '鯿' => ' biān', + '鰁' => ' quán', + '鮙' => ' tà', + '鱂' => ' jiāng', + '鱌' => ' xiàng', + '鱋' => ' qū', + '鱊' => ' yù', + '鱉' => ' biē', + '鱈' => ' xuě', + '鱇' => ' kāng', + '鱆' => ' zhāng', + '鱅' => ' yōng', + '鱄' => ' zhuān', + '鱃' => ' xiū', + '鱁' => ' zhú', + '鱎' => ' jiǎo', + '鱀' => ' jì', + '鰿' => ' jì', + '鰾' => ' biào', + '鰽' => ' qiú', + '鰼' => ' xí', + '鰻' => ' mán', + '鰺' => ' shēn', + '鰹' => ' jiān', + '鰸' => ' qū', + '鰷' => ' tiáo', + '鱍' => ' bō', + '鱏' => ' xún', + '鰵' => ' mǐn', + '鱜' => ' xiang', + '鱦' => ' yìng', + '鱥' => ' guì', + '鱤' => ' gǎn', + '鱣' => ' zhān', + '鱢' => ' sāo', + '鱡' => ' zéi', + '鱠' => ' kuài', + '鱟' => ' hòu', + '鱞' => ' guān', + '鱝' => ' fèn', + '鱛' => ' zeng', + '鱐' => ' sù', + '鱚' => ' xǐ', + '鱙' => ' miáo', + '鱘' => ' xún', + '鱗' => ' lín', + '鱖' => ' guì', + '鱕' => ' fān', + '鱔' => ' shàn', + '鱓' => ' shàn', + '鱒' => ' zūn', + '鱑' => ' huáng', + '鰶' => ' jì', + '鰴' => ' huī', + '鰂' => ' zéi', + '鰎' => ' jiǎn', + '鰘' => ' shi', + '鰗' => ' hú', + '鰖' => ' tuǒ', + '鰕' => ' xiā', + '鰔' => ' gǎn', + '鰓' => ' sāi', + '鰒' => ' fù', + '鰑' => ' yáng', + '鰐' => ' è', + '鰏' => ' bī', + '鰍' => ' qiū', + '鰚' => ' xuan', + '鰌' => ' qiū', + '鰋' => ' yǎn', + '鰊' => ' liàn', + '鰉' => ' huáng', + '鰈' => ' dié', + '鰇' => ' róu', + '鰆' => ' chūn', + '鰅' => ' yú', + '鰄' => ' wēi', + '鰃' => ' wēi', + '鰙' => ' ruò', + '鰛' => ' wēn', + '鰳' => ' lè', + '鰨' => ' tǎ', + '鰲' => ' áo', + '鰱' => ' lián', + '鰰' => ' shen', + '鰯' => ' ruò', + '鰮' => ' wēn', + '鰭' => ' qí', + '鰬' => ' qián', + '鰫' => ' yóng', + '鰪' => ' é', + '鰩' => ' yáo', + '鰧' => ' téng', + '鰜' => ' qiàn', + '鰦' => ' zī', + '鰥' => ' guān', + '鰤' => ' shī', + '鰣' => ' shí', + '鰢' => ' mǎ', + '鰡' => ' liú', + '鰠' => ' sāo', + '鰟' => ' fáng', + '鰞' => ' wū', + '鰝' => ' hào', + '鮚' => ' jié', + '鮘' => ' dai', + '髉' => ' bó', + '鬉' => ' zōng', + '鬓' => ' bìn', + '鬒' => ' zhěn', + '鬑' => ' lián', + '鬐' => ' qí', + '鬏' => ' jiū', + '鬎' => ' là', + '鬍' => ' hú', + '鬌' => ' tuǒ', + '鬋' => ' jiǎn', + '鬊' => ' shùn', + '鬈' => ' quán', + '鬕' => ' mà', + '鬇' => ' zhēng', + '鬆' => ' sōng', + '鬅' => ' péng', + '鬄' => ' dí', + '鬃' => ' zōng', + '鬂' => ' bìn', + '鬁' => ' lì', + '鬀' => ' tì', + '髿' => ' suō', + '髾' => ' shāo', + '鬔' => ' péng', + '鬖' => ' sān', + '髼' => ' péng', + '鬣' => ' liè', + '鬭' => ' dòu', + '鬬' => ' dòu', + '鬫' => ' hǎn', + '鬪' => ' dòu', + '鬩' => ' xì', + '鬨' => ' hòng', + '鬧' => ' nào', + '鬦' => ' dòu', + '鬥' => ' dòu', + '鬤' => ' ráng', + '鬢' => ' bìn', + '鬗' => ' mán', + '鬡' => ' níng', + '鬠' => ' kuò', + '鬟' => ' huán', + '鬞' => ' náng', + '鬝' => ' qiān', + '鬜' => ' qiān', + '鬛' => ' liè', + '鬚' => ' xū', + '鬙' => ' sēng', + '鬘' => ' mán', + '髽' => ' zhuā', + '髻' => ' jì', + '鬯' => ' chàng', + '髕' => ' bìn', + '髟' => ' biāo', + '髞' => ' sào', + '髝' => ' láo', + '髜' => ' qiǎo', + '髛' => ' kāo', + '髚' => ' qiào', + '髙' => ' gāo', + '高' => ' gāo', + '髗' => ' lú', + '髖' => ' kuān', + '體' => ' tǐ', + '髡' => ' kūn', + '髓' => ' suǐ', + '髒' => ' zāng', + '髑' => ' dú', + '髐' => ' xiāo', + '髏' => ' lóu', + '髎' => ' liáo', + '髍' => ' mó', + '髌' => ' bìn', + '髋' => ' kuān', + '髊' => ' cī', + '髠' => ' kūn', + '髢' => ' dí', + '髺' => ' kuò', + '髯' => ' rán', + '髹' => ' xiū', + '髸' => ' gōng', + '髷' => ' qū', + '髶' => ' róng', + '髵' => ' ér', + '髴' => ' fú', + '髳' => ' máo', + '髲' => ' bì', + '髱' => ' bào', + '髰' => ' tì', + '髮' => ' fà', + '髣' => ' fǎng', + '髭' => ' zī', + '髬' => ' pī', + '髫' => ' tiáo', + '髪' => ' fà', + '髩' => ' bìn', + '髨' => ' kūn', + '髧' => ' dàn', + '髦' => ' máo', + '髥' => ' rán', + '髤' => ' xiū', + '鬮' => ' jiū', + '鬰' => ' yù', + '鮗' => ' dong', + '魲' => ' lú', + '魼' => ' qū', + '魻' => ' xiá', + '魺' => ' hé', + '魹' => ' mo', + '魸' => ' pian', + '魷' => ' yóu', + '魶' => ' nà', + '魵' => ' fén', + '魴' => ' fáng', + '魳' => ' zā', + '魱' => ' hú', + '魾' => ' pī', + '魰' => ' wén', + '魯' => ' lǔ', + '魮' => ' pí', + '魭' => ' yuán', + '魬' => ' bǎn', + '魫' => ' shěn', + '魪' => ' jiè', + '魩' => ' mò', + '魨' => ' tún', + '魧' => ' háng', + '魽' => ' hán', + '魿' => ' líng', + '魥' => ' è', + '鮌' => ' gǔn', + '鮖' => ' shi', + '鮕' => ' gū', + '鮔' => ' jù', + '鮓' => ' zhǎ', + '鮒' => ' fù', + '鮑' => ' bào', + '鮐' => ' tái', + '鮏' => ' xīng', + '鮎' => ' nián', + '鮍' => ' pī', + '鮋' => ' yóu', + '鮀' => ' tuó', + '鮊' => ' bà', + '鮉' => ' diāo', + '鮈' => ' jū', + '鮇' => ' wèi', + '鮆' => ' cǐ', + '鮅' => ' bì', + '鮄' => ' fú', + '鮃' => ' píng', + '鮂' => ' qiú', + '鮁' => ' bō', + '魦' => ' shā', + '魤' => ' é', + '鬱' => ' yù', + '鬽' => ' mèi', + '魇' => ' yǎn', + '魆' => ' xū', + '魅' => ' mèi', + '魄' => ' pò', + '魃' => ' bá', + '魂' => ' hún', + '魁' => ' kuí', + '魀' => ' gà', + '鬿' => ' qí', + '鬾' => ' jì', + '鬼' => ' guǐ', + '魉' => ' liǎng', + '鬻' => ' yù', + '鬺' => ' shāng', + '鬹' => ' guī', + '鬸' => ' liù', + '鬷' => ' zōng', + '鬶' => ' guī', + '鬵' => ' qín', + '鬴' => ' fǔ', + '鬳' => ' yàn', + '鬲' => ' gé', + '魈' => ' xiāo', + '魊' => ' yù', + '魣' => ' xù', + '魘' => ' yǎn', + '魢' => ' jǐ', + '魡' => ' diào', + '魠' => ' tuō', + '魟' => ' hóng', + '魞' => ' ba', + '魝' => ' jié', + '魜' => ' rén', + '魛' => ' dāo', + '魚' => ' yú', + '魙' => ' zhān', + '魗' => ' chǒu', + '魋' => ' tuí', + '魖' => ' xū', + '魕' => ' jǐ', + '魔' => ' mó', + '魓' => ' bì', + '魒' => ' piāo', + '魑' => ' chī', + '魐' => ' gān', + '魏' => ' wèi', + '魎' => ' liǎng', + '魍' => ' wǎng', + '魌' => ' qī', + '銨' => ' ǎn', + '銦' => ' yīn', + '薥' => ' shǔ', + '觶' => ' zhì', + '言' => ' yán', + '觿' => ' xī', + '觾' => ' yàn', + '觽' => ' xī', + '觼' => ' jué', + '觻' => ' lì', + '觺' => ' yí', + '觹' => ' xī', + '觸' => ' chù', + '觷' => ' xué', + '觵' => ' gōng', + '訂' => ' dìng', + '觴' => ' shāng', + '觳' => ' hú', + '觲' => ' xīng', + '觱' => ' bì', + '觰' => ' zhā', + '觯' => ' zhì', + '觮' => ' lù', + '觭' => ' jī', + '觬' => ' ní', + '觫' => ' sù', + '訁' => ' yán', + '訃' => ' fù', + '觩' => ' qiú', + '訐' => ' jié', + '訚' => ' yín', + '訙' => ' xùn', + '記' => ' jì', + '託' => ' tuō', + '訖' => ' qì', + '訕' => ' shàn', + '訔' => ' yín', + '訓' => ' xùn', + '訒' => ' rèn', + '訑' => ' yí', + '訏' => ' xū', + '訄' => ' qiú', + '討' => ' tǎo', + '訍' => ' chài', + '訌' => ' hòng', + '訋' => ' diào', + '訊' => ' xùn', + '訉' => ' fān', + '計' => ' jì', + '訇' => ' hōng', + '訆' => ' jiào', + '訅' => ' qiú', + '觪' => ' xīng', + '觨' => ' hùn', + '訜' => ' fēn', + '观' => ' guān', + '觌' => ' dí', + '觋' => ' xí', + '觊' => ' jì', + '觉' => ' jué', + '览' => ' lǎn', + '觇' => ' chān', + '视' => ' shì', + '觅' => ' mì', + '规' => ' guī', + '觃' => ' yàn', + '见' => ' jiàn', + '觎' => ' yú', + '觀' => ' guān', + '覿' => ' dí', + '覾' => ' shěn', + '覽' => ' lǎn', + '覼' => ' luó', + '覻' => ' qū', + '覺' => ' jué', + '覹' => ' wéi', + '覸' => ' jiān', + '覷' => ' qù', + '觍' => ' tiǎn', + '觏' => ' gòu', + '觧' => ' jiě', + '觜' => ' zī', + '触' => ' chù', + '觥' => ' gōng', + '觤' => ' guǐ', + '解' => ' jiě', + '觢' => ' shì', + '觡' => ' gé', + '觠' => ' quán', + '觟' => ' huà', + '觞' => ' shāng', + '觝' => ' dǐ', + '觛' => ' dàn', + '觐' => ' jìn', + '觚' => ' gū', + '觙' => ' jí', + '觘' => ' chào', + '觗' => ' zhì', + '觖' => ' jué', + '觕' => ' cū', + '觔' => ' jīn', + '觓' => ' qiú', + '角' => ' jiǎo', + '觑' => ' qù', + '訛' => ' é', + '訝' => ' yà', + '覵' => ' jiàn', + '詞' => ' cí', + '詨' => ' xiào', + '詧' => ' chá', + '試' => ' shì', + '詥' => ' hé', + '詤' => ' huǎng', + '詣' => ' yì', + '詢' => ' xún', + '詡' => ' xǔ', + '詠' => ' yǒng', + '詟' => ' zhé', + '詝' => ' zhǔ', + '詪' => ' hěn', + '詜' => ' tāo', + '詛' => ' zǔ', + '詚' => ' dá', + '詙' => ' bá', + '詘' => ' qū', + '詗' => ' xiòng', + '詖' => ' bì', + '評' => ' píng', + '詔' => ' zhào', + '詓' => ' qǔ', + '詩' => ' shī', + '詫' => ' chà', + '詑' => ' yí', + '詸' => ' mí', + '誂' => ' tiǎo', + '誁' => ' bìng', + '誀' => ' èr', + '詿' => ' guà', + '詾' => ' xiōng', + '詽' => ' yán', + '詼' => ' huī', + '詻' => ' è', + '詺' => ' mìng', + '詹' => ' zhān', + '詷' => ' tóng', + '詬' => ' gòu', + '詶' => ' zhòu', + '詵' => ' shēn', + '詴' => ' wēi', + '詳' => ' xiáng', + '該' => ' gāi', + '話' => ' huà', + '詰' => ' jié', + '詯' => ' huì', + '詮' => ' quán', + '詭' => ' guǐ', + '詒' => ' yí', + '詐' => ' zhà', + '訞' => ' yāo', + '訪' => ' fǎng', + '訴' => ' sù', + '訳' => ' yì', + '訲' => ' yì', + '許' => ' xǔ', + '訰' => ' zhùn', + '訯' => ' sǎ', + '訮' => ' xiān', + '設' => ' shè', + '訬' => ' chāo', + '訫' => ' xìn', + '訩' => ' xiōng', + '訶' => ' hē', + '訨' => ' zhǐ', + '訧' => ' yóu', + '訦' => ' chén', + '訥' => ' nè', + '訤' => ' xiáo', + '訣' => ' jué', + '訢' => ' xīn', + '訡' => ' yín', + '訠' => ' shěn', + '訟' => ' sòng', + '訵' => ' chī', + '訷' => ' shēn', + '詏' => ' yào', + '詄' => ' dié', + '詎' => ' jù', + '詍' => ' yì', + '詌' => ' gàn', + '詋' => ' zhòu', + '詊' => ' pàn', + '詉' => ' náo', + '詈' => ' lì', + '詇' => ' yàng', + '詆' => ' dǐ', + '詅' => ' líng', + '詃' => ' jiǎn', + '訸' => ' hé', + '詂' => ' fù', + '詁' => ' gǔ', + '詀' => ' zhān', + '訿' => ' zǐ', + '訾' => ' zī', + '訽' => ' gòu', + '証' => ' zhèng', + '註' => ' zhù', + '診' => ' zhěn', + '訹' => ' xù', + '覶' => ' luó', + '覴' => ' dēng', + '誄' => ' lěi', + '褦' => ' nài', + '褰' => ' qiān', + '褯' => ' jiè', + '褮' => ' yīng', + '褭' => ' niǎo', + '褬' => ' sǎng', + '褫' => ' chǐ', + '褪' => ' tuì', + '褩' => ' bān', + '褨' => ' suǒ', + '褧' => ' jiǒng', + '褥' => ' rù', + '褲' => ' kù', + '褤' => ' yuàn', + '褣' => ' róng', + '褢' => ' huái', + '褡' => ' dā', + '褠' => ' gōu', + '褟' => ' tā', + '褞' => ' yǔn', + '褝' => ' dān', + '褜' => ' pao', + '褛' => ' lǚ', + '褱' => ' huái', + '褳' => ' lián', + '褙' => ' bèi', + '襀' => ' jī', + '襊' => ' cuì', + '襉' => ' jiǎn', + '襈' => ' zhuàn', + '襇' => ' jiǎn', + '襆' => ' fú', + '襅' => ' bi', + '襄' => ' xiāng', + '襃' => ' bāo', + '襂' => ' sēn', + '襁' => ' qiǎng', + '褿' => ' cáo', + '褴' => ' lán', + '褾' => ' biǎo', + '褽' => ' wèi', + '褼' => ' xiān', + '褻' => ' xiè', + '褺' => ' diē', + '褹' => ' yì', + '褸' => ' lǚ', + '褷' => ' shī', + '褶' => ' zhě', + '褵' => ' lí', + '褚' => ' chǔ', + '褘' => ' huī', + '襌' => ' dān', + '裲' => ' liǎng', + '裼' => ' tì', + '裻' => ' dú', + '裺' => ' yǎn', + '裹' => ' guǒ', + '裸' => ' luǒ', + '裷' => ' yuān', + '裶' => ' fēi', + '裵' => ' péi', + '裴' => ' péi', + '裳' => ' shang', + '裱' => ' biǎo', + '裾' => ' jū', + '裰' => ' duō', + '裯' => ' chóu', + '裮' => ' chāng', + '裭' => ' chǐ', + '裬' => ' líng', + '裫' => ' yuàn', + '裪' => ' táo', + '裩' => ' kūn', + '裨' => ' bì', + '裧' => ' chān', + '製' => ' zhì', + '裿' => ' yǐ', + '褗' => ' yǎn', + '褌' => ' kūn', + '褖' => ' tuàn', + '褕' => ' yú', + '褔' => ' fù', + '褓' => ' bǎo', + '褒' => ' bāo', + '褑' => ' yuàn', + '褐' => ' hè', + '褏' => ' xiù', + '褎' => ' xiù', + '褍' => ' duān', + '褋' => ' dié', + '褀' => ' jì', + '褊' => ' biǎn', + '褉' => ' xiè', + '褈' => ' chóng', + '複' => ' fù', + '褆' => ' tí', + '褅' => ' tì', + '褄' => ' qi', + '褃' => ' kèn', + '褂' => ' guà', + '褁' => ' zhí', + '襋' => ' jí', + '襍' => ' zá', + '観' => ' guān', + '覎' => ' yàn', + '覘' => ' chān', + '覗' => ' sì', + '視' => ' shì', + '覕' => ' miè', + '覔' => ' mì', + '覓' => ' mì', + '覒' => ' mào', + '覑' => ' piǎn', + '覐' => ' jué', + '規' => ' guī', + '覍' => ' biàn', + '覚' => ' jué', + '覌' => ' guān', + '見' => ' jiàn', + '覊' => ' jī', + '覉' => ' jī', + '覈' => ' hé', + '覇' => ' bà', + '覆' => ' fù', + '覅' => ' fiào', + '覄' => ' fu', + '覃' => ' tán', + '覙' => ' luó', + '覛' => ' mì', + '要' => ' yào', + '覨' => ' è', + '覲' => ' jìn', + '覱' => ' zhàn', + '覰' => ' qū', + '覯' => ' gòu', + '覮' => ' yíng', + '覭' => ' míng', + '覬' => ' jì', + '覫' => ' pǎng', + '親' => ' qīn', + '覩' => ' dǔ', + '覧' => ' lǎn', + '覜' => ' tiào', + '覦' => ' yú', + '覥' => ' tiǎn', + '覤' => ' xì', + '覣' => ' wēi', + '覢' => ' shǎn', + '覡' => ' xí', + '覠' => ' jūn', + '覟' => ' zhì', + '覞' => ' yào', + '覝' => ' lián', + '覂' => ' fěng', + '覀' => ' xī', + '襎' => ' fán', + '襚' => ' suì', + '襤' => ' lán', + '襣' => ' bì', + '襢' => ' tǎn', + '襡' => ' shǔ', + '襠' => ' dāng', + '襟' => ' jīn', + '襞' => ' bì', + '襝' => ' liǎn', + '襜' => ' chān', + '襛' => ' nóng', + '襙' => ' cào', + '襦' => ' rú', + '襘' => ' guì', + '襗' => ' zé', + '襖' => ' ǎo', + '襕' => ' lán', + '襔' => ' mǎn', + '襓' => ' ráo', + '襒' => ' bié', + '襑' => ' xín', + '襐' => ' xiàng', + '襏' => ' bó', + '襥' => ' pú', + '襧' => ' zhǐ', + '西' => ' xī', + '襴' => ' lán', + '襾' => ' yà', + '襽' => ' lan', + '襼' => ' yì', + '襻' => ' pàn', + '襺' => ' jiǎn', + '襹' => ' shī', + '襸' => ' zàn', + '襷' => ' ju', + '襶' => ' dài', + '襵' => ' zhě', + '襳' => ' xiān', + '襨' => ' dùi', + '襲' => ' xí', + '襱' => ' lóng', + '襰' => ' lài', + '襯' => ' chèn', + '襮' => ' bó', + '襭' => ' xié', + '襬' => ' bǎi', + '襫' => ' shì', + '襪' => ' wà', + '襩' => ' shǔ', + '誃' => ' yí', + '誅' => ' zhū', + '裥' => ' jiǎn', + '讖' => ' chèn', + '讠' => ' yán', + '讟' => ' dú', + '讞' => ' yàn', + '讝' => ' zhán', + '讜' => ' dǎng', + '讛' => ' yì', + '讚' => ' zàn', + '讙' => ' huān', + '讘' => ' niè', + '讗' => ' xié', + '讕' => ' lán', + '订' => ' dìng', + '讔' => ' yǐn', + '讓' => ' ràng', + '讒' => ' chán', + '讑' => ' yào', + '讐' => ' chóu', + '讏' => ' wèi', + '讎' => ' chóu', + '讍' => ' è', + '讌' => ' yàn', + '讋' => ' zhé', + '计' => ' jì', + '讣' => ' fù', + '讉' => ' yí', + '记' => ' jì', + '论' => ' lùn', + '讹' => ' é', + '许' => ' xǔ', + '讷' => ' nè', + '讶' => ' yà', + '讵' => ' jù', + '讴' => ' ōu', + '讳' => ' huì', + '讲' => ' jiǎng', + '讱' => ' rèn', + '讯' => ' xùn', + '认' => ' rèn', + '议' => ' yì', + '训' => ' xùn', + '讬' => ' tuō', + '讫' => ' qì', + '讪' => ' shàn', + '让' => ' ràng', + '讨' => ' tǎo', + '讧' => ' hòng', + '讦' => ' jié', + '讥' => ' jī', + '變' => ' biàn', + '讈' => ' lì', + '讼' => ' sòng', + '譢' => ' suì', + '譬' => ' pì', + '譫' => ' zhān', + '譪' => ' ài', + '譩' => ' yī', + '譨' => ' náng', + '譧' => ' zhàn', + '警' => ' jǐng', + '譥' => ' jiào', + '譤' => ' jī', + '譣' => ' xiǎn', + '譡' => ' dǎng', + '譮' => ' huà', + '譠' => ' tán', + '譟' => ' zào', + '譞' => ' xuān', + '譝' => ' shéng', + '譜' => ' pǔ', + '譛' => ' zèn', + '譚' => ' tán', + '譙' => ' qiào', + '識' => ' shí', + '譗' => ' zhá', + '譭' => ' huǐ', + '譯' => ' yì', + '讇' => ' chǎn', + '譼' => ' jiàn', + '讆' => ' wèi', + '讅' => ' shěn', + '讄' => ' lěi', + '讃' => ' zàn', + '讂' => ' xuàn', + '讁' => ' zhé', + '讀' => ' dú', + '譿' => ' huì', + '譾' => ' jiǎn', + '譽' => ' yù', + '譻' => ' yīng', + '議' => ' yì', + '譺' => ' ài', + '譹' => ' háo', + '譸' => ' zhōu', + '護' => ' hù', + '譶' => ' tà', + '譵' => ' zhuì', + '譴' => ' qiǎn', + '譳' => ' nòu', + '譲' => ' ràng', + '譱' => ' shàn', + '讻' => ' xiōng', + '讽' => ' fěng', + '譕' => ' wú', + '课' => ' kè', + '谈' => ' tán', + '谇' => ' suì', + '谆' => ' zhūn', + '谅' => ' liàng', + '谄' => ' chǎn', + '调' => ' diào', + '谂' => ' shěn', + '谁' => ' shuí', + '谀' => ' yú', + '诿' => ' wěi', + '诽' => ' fěi', + '谊' => ' yì', + '诼' => ' zhuó', + '读' => ' dú', + '诺' => ' nuò', + '诹' => ' zōu', + '诸' => ' zhū', + '请' => ' qǐng', + '诶' => ' éi', + '诵' => ' sòng', + '说' => ' shuō', + '诳' => ' kuáng', + '谉' => ' shěn', + '谋' => ' móu', + '诱' => ' yòu', + '谘' => ' zī', + '谢' => ' xiè', + '谡' => ' sù', + '谠' => ' dǎng', + '谟' => ' mó', + '谞' => ' xū', + '谝' => ' piǎn', + '谜' => ' mí', + '谛' => ' dì', + '谚' => ' yàn', + '谙' => ' ān', + '谗' => ' chán', + '谌' => ' chén', + '谖' => ' xuān', + '谕' => ' yù', + '谔' => ' è', + '谓' => ' wèi', + '谒' => ' yè', + '谑' => ' xuè', + '谐' => ' xié', + '谏' => ' jiàn', + '谎' => ' huǎng', + '谍' => ' dié', + '诲' => ' huì', + '诰' => ' gào', + '设' => ' shè', + '诊' => ' zhěn', + '诔' => ' lěi', + '诓' => ' kuāng', + '诒' => ' yí', + '译' => ' yì', + '诐' => ' bì', + '诏' => ' zhào', + '诎' => ' qū', + '词' => ' cí', + '诌' => ' zhōu', + '诋' => ' dǐ', + '诉' => ' sù', + '诖' => ' guà', + '诈' => ' zhà', + '诇' => ' xiòng', + '识' => ' shí', + '诅' => ' zǔ', + '评' => ' píng', + '诃' => ' hē', + '诂' => ' gǔ', + '证' => ' zhèng', + '诀' => ' jué', + '访' => ' fǎng', + '试' => ' shì', + '诗' => ' shī', + '误' => ' wù', + '诤' => ' zhēng', + '诮' => ' qiào', + '语' => ' yǔ', + '诬' => ' wū', + '诫' => ' jiè', + '诪' => ' zhōu', + '诩' => ' xǔ', + '诨' => ' hùn', + '诧' => ' chà', + '详' => ' xiáng', + '该' => ' gāi', + '诣' => ' yì', + '诘' => ' jí', + '询' => ' xún', + '诡' => ' guǐ', + '诠' => ' quán', + '诟' => ' gòu', + '殚' => ' dān', + '话' => ' huà', + '诜' => ' shēn', + '诛' => ' zhū', + '诚' => ' chéng', + '诙' => ' huī', + '譖' => ' zèn', + '譔' => ' zhuàn', + '誆' => ' kuāng', + '諆' => ' qī', + '諐' => ' qiān', + '諏' => ' zōu', + '諎' => ' zé', + '諍' => ' zhèng', + '諌' => ' dǒng', + '請' => ' qǐng', + '諊' => ' jú', + '諉' => ' wěi', + '諈' => ' zhuì', + '談' => ' tán', + '諅' => ' jì', + '諒' => ' liàng', + '諄' => ' zhūn', + '諃' => ' chēn', + '諂' => ' chǎn', + '諁' => ' zhuó', + '諀' => ' pǐ', + '調' => ' diào', + '誾' => ' yín', + '誽' => ' nì', + '誼' => ' yì', + '誻' => ' tà', + '諑' => ' zhuó', + '諓' => ' jiàn', + '誹' => ' fěi', + '諠' => ' xuān', + '諪' => ' tíng', + '諩' => ' pǔ', + '諨' => ' fú', + '諧' => ' xié', + '諦' => ' dì', + '諥' => ' zhòng', + '諤' => ' è', + '諣' => ' huà', + '諢' => ' hùn', + '諡' => ' shì', + '諟' => ' shì', + '諔' => ' chù', + '諞' => ' piǎn', + '諝' => ' xū', + '諜' => ' dié', + '諛' => ' yú', + '諚' => ' pián', + '諙' => ' huài', + '諘' => ' biǎo', + '諗' => ' shěn', + '論' => ' lùn', + '諕' => ' háo', + '誺' => ' chī', + '誸' => ' xián', + '諬' => ' qǐ', + '誒' => ' éi', + '誜' => ' shuà', + '誛' => ' qīn', + '誚' => ' qiào', + '誙' => ' kēng', + '誘' => ' yòu', + '誗' => ' chán', + '誖' => ' bèi', + '誕' => ' dàn', + '誔' => ' tǐng', + '誓' => ' shì', + '誑' => ' kuáng', + '語' => ' yǔ', + '誐' => ' é', + '誏' => ' lǎng', + '誎' => ' cù', + '認' => ' rèn', + '誌' => ' zhì', + '誋' => ' jì', + '誊' => ' téng', + '誉' => ' yù', + '誈' => ' wú', + '誇' => ' kuā', + '誝' => ' ān', + '誟' => ' xiào', + '誷' => ' wǎng', + '説' => ' shuō', + '誶' => ' suì', + '誵' => ' xiáo', + '誴' => ' cóng', + '誳' => ' qū', + '課' => ' kè', + '誱' => ' jié', + '誰' => ' shuí', + '誯' => ' chàng', + '誮' => ' hua', + '読' => ' dú', + '誫' => ' zhèn', + '誠' => ' chéng', + '說' => ' shuō', + '誩' => ' jìng', + '誨' => ' huì', + '誧' => ' bū', + '誦' => ' sòng', + '誥' => ' gào', + '誤' => ' wù', + '誣' => ' wū', + '誢' => ' xiàn', + '誡' => ' jiè', + '諫' => ' jiàn', + '諭' => ' yù', + '譓' => ' huì', + '謮' => ' zé', + '謸' => ' áo', + '謷' => ' áo', + '謶' => ' zhuó', + '謵' => ' xí', + '謴' => ' gùn', + '謳' => ' ōu', + '謲' => ' càn', + '謱' => ' lóu', + '謰' => ' lián', + '謯' => ' jiē', + '謭' => ' jiǎn', + '謺' => ' zhé', + '謬' => ' miù', + '謫' => ' zhé', + '謪' => ' shāng', + '謩' => ' mò', + '謨' => ' mó', + '謧' => ' lí', + '謦' => ' qìng', + '謥' => ' còng', + '謤' => ' biāo', + '謣' => ' yú', + '謹' => ' jǐn', + '謻' => ' yí', + '謡' => ' yáo', + '譈' => ' duì', + '譒' => ' bò', + '譑' => ' jiǎo', + '譐' => ' zǔn', + '譏' => ' jī', + '譎' => ' jué', + '譍' => ' yīng', + '譌' => ' é', + '譋' => ' lán', + '譊' => ' náo', + '證' => ' zhèng', + '譇' => ' zhā', + '謼' => ' hū', + '譆' => ' xī', + '譅' => ' sè', + '譄' => ' zēng', + '譃' => ' xū', + '譂' => ' chǎn', + '譁' => ' huá', + '譀' => ' hàn', + '謿' => ' cháo', + '謾' => ' mán', + '謽' => ' jiàng', + '謢' => ' zhi', + '謠' => ' yáo', + '諮' => ' zī', + '諺' => ' yàn', + '謄' => ' téng', + '謃' => ' xing', + '謂' => ' wèi', + '謁' => ' yè', + '謀' => ' móu', + '諿' => ' qī', + '諾' => ' nuò', + '諽' => ' gé', + '諼' => ' xuān', + '諻' => ' huáng', + '諹' => ' yáng', + '謆' => ' shàn', + '諸' => ' zhū', + '諷' => ' fěng', + '諶' => ' chén', + '諵' => ' nán', + '諴' => ' xián', + '諳' => ' ān', + '諲' => ' yīn', + '諱' => ' huì', + '諰' => ' xǐ', + '諯' => ' zhuān', + '謅' => ' zhōu', + '謇' => ' jiǎn', + '謟' => ' tāo', + '謔' => ' xuè', + '謞' => ' hè', + '謝' => ' xiè', + '謜' => ' yuán', + '講' => ' jiǎng', + '謚' => ' shì', + '謙' => ' qiān', + '謘' => ' chí', + '謗' => ' bàng', + '謖' => ' sù', + '謕' => ' tí', + '謓' => ' chēn', + '謈' => ' pó', + '謒' => ' qiāng', + '謑' => ' xǐ', + '謐' => ' mì', + '謏' => ' xiǎo', + '謎' => ' mí', + '謍' => ' yíng', + '謌' => ' gē', + '謋' => ' huò', + '謊' => ' huǎng', + '謉' => ' kuì', + '裦' => ' fóu', + '裤' => ' kù', + '谤' => ' bàng', + '蚵' => ' hé', + '蚿' => ' xián', + '蚾' => ' pí', + '蚽' => ' pí', + '蚼' => ' gǒu', + '蚻' => ' zhá', + '蚺' => ' rán', + '蚹' => ' fù', + '蚸' => ' lì', + '蚷' => ' jù', + '蚶' => ' hān', + '蚴' => ' yòu', + '蛁' => ' diāo', + '蚳' => ' chí', + '蚲' => ' píng', + '蚱' => ' zhà', + '蚰' => ' yóu', + '蚯' => ' qiū', + '蚮' => ' tè', + '蚭' => ' ní', + '蚬' => ' xiǎn', + '蚫' => ' bào', + '蚪' => ' dǒu', + '蛀' => ' zhù', + '蛂' => ' bié', + '蚨' => ' fú', + '蛏' => ' chēng', + '蛙' => ' wā', + '蛘' => ' yáng', + '蛗' => ' fù', + '蛖' => ' máng', + '蛕' => ' huí', + '蛔' => ' huí', + '蛓' => ' cì', + '蛒' => ' gé', + '蛑' => ' móu', + '蛐' => ' qū', + '蛎' => ' lì', + '蛃' => ' bǐng', + '蛍' => ' yíng', + '蛌' => ' gǔ', + '蛋' => ' dàn', + '蛊' => ' gǔ', + '蛉' => ' líng', + '蛈' => ' tiě', + '蛇' => ' shé', + '蛆' => ' qū', + '蛅' => ' zhān', + '蛄' => ' gū', + '蚩' => ' chī', + '蚧' => ' jiè', + '蛛' => ' zhū', + '蚁' => ' yǐ', + '蚋' => ' ruì', + '蚊' => ' wén', + '蚉' => ' wén', + '蚈' => ' qiān', + '蚇' => ' chǐ', + '蚆' => ' bā', + '蚅' => ' è', + '蚄' => ' fāng', + '蚃' => ' xiàng', + '蚂' => ' mǎ', + '蚀' => ' shí', + '蚍' => ' pí', + '虿' => ' chài', + '虾' => ' xiā', + '虽' => ' suī', + '虼' => ' gè', + '虻' => ' méng', + '虺' => ' huī', + '虹' => ' hóng', + '虸' => ' zǐ', + '虷' => ' hán', + '虶' => ' yū', + '蚌' => ' bàng', + '蚎' => ' yuè', + '蚦' => ' rán', + '蚛' => ' zhòng', + '蚥' => ' fù', + '蚤' => ' zǎo', + '蚣' => ' gōng', + '蚢' => ' háng', + '蚡' => ' fén', + '蚠' => ' fén', + '蚟' => ' wáng', + '蚞' => ' mù', + '蚝' => ' háo', + '蚜' => ' yá', + '蚚' => ' qí', + '蚏' => ' yuè', + '蚙' => ' qín', + '蚘' => ' huí', + '蚗' => ' jué', + '蚖' => ' yuán', + '蚕' => ' cán', + '蚔' => ' qí', + '蚓' => ' yǐn', + '蚒' => ' tóng', + '蚑' => ' qí', + '蚐' => ' jūn', + '蛚' => ' liè', + '蛜' => ' yī', + '虴' => ' zhé', + '蜝' => ' qí', + '蜧' => ' lì', + '蜦' => ' lún', + '蜥' => ' xī', + '蜤' => ' sī', + '蜣' => ' qiāng', + '蜢' => ' měng', + '蜡' => ' là', + '蜠' => ' jùn', + '蜟' => ' yù', + '蜞' => ' qí', + '蜜' => ' mì', + '蜩' => ' tiáo', + '蜛' => ' jū', + '蜚' => ' fēi', + '蜙' => ' sōng', + '蜘' => ' zhī', + '蜗' => ' wō', + '蜖' => ' huí', + '蜕' => ' tuì', + '蜔' => ' diàn', + '蜓' => ' tíng', + '蜒' => ' yán', + '蜨' => ' dié', + '蜪' => ' táo', + '蜐' => ' jié', + '蜷' => ' quán', + '蝁' => ' è', + '蝀' => ' dōng', + '蜿' => ' wān', + '蜾' => ' guǒ', + '蜽' => ' liǎng', + '蜼' => ' wèi', + '蜻' => ' qīng', + '蜺' => ' ní', + '蜹' => ' ruì', + '蜸' => ' qiǎn', + '蜶' => ' suò', + '蜫' => ' kūn', + '蜵' => ' yuān', + '蜴' => ' yì', + '蜳' => ' dūn', + '蜲' => ' wēi', + '蜱' => ' pí', + '蜰' => ' féi', + '蜯' => ' bàng', + '蜮' => ' yù', + '蜭' => ' hàn', + '蜬' => ' hán', + '蜑' => ' dàn', + '蜏' => ' yǒu', + '蛝' => ' xián', + '蛩' => ' qióng', + '蛳' => ' sī', + '蛲' => ' náo', + '蛱' => ' jiá', + '蛰' => ' zhé', + '蛯' => ' lao', + '蛮' => ' mán', + '蛭' => ' zhì', + '蛬' => ' qióng', + '蛫' => ' guǐ', + '蛪' => ' qiè', + '蛨' => ' mò', + '蛵' => ' xīng', + '蛧' => ' wǎng', + '蛦' => ' yí', + '蛥' => ' shé', + '蛤' => ' há', + '蛣' => ' qī', + '蛢' => ' píng', + '蛡' => ' yì', + '蛠' => ' lì', + '蛟' => ' jiāo', + '蛞' => ' kuò', + '蛴' => ' qí', + '蛶' => ' jiè', + '蜎' => ' yuān', + '蜃' => ' shèn', + '蜍' => ' chú', + '蜌' => ' bì', + '蜋' => ' láng', + '蜊' => ' lí', + '蜉' => ' fú', + '蜈' => ' wú', + '蜇' => ' zhē', + '蜆' => ' xiàn', + '蜅' => ' fǔ', + '蜄' => ' shèn', + '蜂' => ' fēng', + '蛷' => ' qiú', + '蜁' => ' xuán', + '蜀' => ' shǔ', + '蛿' => ' hàn', + '蛾' => ' é', + '蛽' => ' bài', + '蛼' => ' chē', + '蛻' => ' tuì', + '蛺' => ' jiá', + '蛹' => ' yǒng', + '蛸' => ' shāo', + '虵' => ' shé', + '虳' => ' jué', + '蝃' => ' dì', + '藥' => ' yào', + '藯' => ' wèi', + '藮' => ' qiáo', + '藭' => ' qióng', + '藬' => ' tuī', + '藫' => ' tán', + '藪' => ' sǒu', + '藩' => ' fān', + '藨' => ' biāo', + '藧' => ' huàn', + '藦' => ' mò', + '藤' => ' téng', + '藱' => ' huì', + '藣' => ' bēi', + '藢' => ' zhǐ', + '藡' => ' dí', + '藠' => ' jiào', + '藟' => ' lěi', + '藞' => ' lǎ', + '藝' => ' yì', + '藜' => ' lí', + '藛' => ' xiě', + '藚' => ' xù', + '藰' => ' liú', + '藲' => ' ou', + '藘' => ' lǘ', + '藿' => ' huò', + '蘉' => ' méng', + '蘈' => ' tuí', + '蘇' => ' sū', + '蘆' => ' lú', + '蘅' => ' héng', + '蘄' => ' qí', + '蘃' => ' ruǐ', + '蘂' => ' ruǐ', + '蘁' => ' wù', + '蘀' => ' tuò', + '藾' => ' lài', + '藳' => ' gǎo', + '藽' => ' qìn', + '藼' => ' xuān', + '藻' => ' zǎo', + '藺' => ' lìn', + '藹' => ' ǎi', + '藸' => ' chú', + '藷' => ' shǔ', + '藶' => ' lì', + '藵' => ' bao', + '藴' => ' yùn', + '藙' => ' yì', + '藗' => ' sù', + '蘋' => ' píng', + '薱' => ' duì', + '薻' => ' zǎo', + '薺' => ' jì', + '薹' => ' tái', + '薸' => ' piáo', + '薷' => ' rú', + '薶' => ' mái', + '薵' => ' chóu', + '薴' => ' níng', + '薳' => ' wěi', + '薲' => ' pín', + '薰' => ' xūn', + '薽' => ' zhēn', + '薯' => ' shǔ', + '薮' => ' sǒu', + '薭' => ' bai', + '薬' => ' yào', + '薫' => ' xūn', + '薪' => ' xīn', + '薩' => ' sà', + '薨' => ' hōng', + '薧' => ' hāo', + '薦' => ' jiàn', + '薼' => ' chén', + '薾' => ' ěr', + '藖' => ' xián', + '藋' => ' diào', + '藕' => ' ǒu', + '藔' => ' liáo', + '藓' => ' xiǎn', + '藒' => ' qiè', + '藑' => ' qióng', + '藐' => ' miǎo', + '藏' => ' cáng', + '藎' => ' jìn', + '藍' => ' lán', + '藌' => ' mì', + '藊' => ' biǎn', + '薿' => ' nǐ', + '藉' => ' jí', + '藈' => ' kuí', + '藇' => ' xù', + '藆' => ' jiǎn', + '藅' => ' fá', + '藄' => ' qí', + '藃' => ' xiāo', + '藂' => ' cóng', + '藁' => ' gǎo', + '藀' => ' yíng', + '蘊' => ' yùn', + '蘌' => ' yǔ', + '虲' => ' xiā', + '虍' => ' hū', + '虗' => ' xū', + '虖' => ' hū', + '處' => ' chù', + '虔' => ' qián', + '虓' => ' xiāo', + '虒' => ' sī', + '虑' => ' lǜ', + '虐' => ' nüè', + '虏' => ' lǔ', + '虎' => ' hǔ', + '虌' => ' biē', + '虙' => ' fú', + '虋' => ' mén', + '虊' => ' luán', + '虉' => ' yì', + '虈' => ' xiāo', + '虇' => ' quǎn', + '虆' => ' léi', + '虅' => ' teng', + '虄' => ' sà', + '虃' => ' jiān', + '虂' => ' lù', + '虘' => ' cuó', + '虚' => ' xū', + '虀' => ' jī', + '虧' => ' kuī', + '虱' => ' shī', + '虰' => ' dīng', + '虯' => ' qiú', + '虮' => ' jǐ', + '虭' => ' diāo', + '虬' => ' qiú', + '虫' => ' chóng', + '虪' => ' shù', + '虩' => ' xì', + '虨' => ' bīn', + '虦' => ' zhàn', + '虛' => ' xū', + '虥' => ' zhàn', + '虤' => ' yán', + '虣' => ' bào', + '虢' => ' guó', + '虡' => ' jù', + '虠' => ' jiāo', + '號' => ' hào', + '虞' => ' yú', + '虝' => ' hǔ', + '虜' => ' lǔ', + '虁' => ' kuí', + '蘿' => ' luó', + '蘍' => ' xūn', + '蘙' => ' yì', + '蘣' => ' tǒu', + '蘢' => ' lóng', + '蘡' => ' yīng', + '蘠' => ' qiáng', + '蘟' => ' yǐn', + '蘞' => ' liǎn', + '蘝' => ' liàn', + '蘜' => ' jú', + '蘛' => ' yú', + '蘚' => ' xiǎn', + '蘘' => ' ráng', + '蘥' => ' yuè', + '蘗' => ' bò', + '蘖' => ' niè', + '蘕' => ' feng', + '蘔' => ' jiōng', + '蘓' => ' sū', + '蘒' => ' qiu', + '蘑' => ' mó', + '蘐' => ' xuān', + '蘏' => ' jiōng', + '蘎' => ' jì', + '蘤' => ' wěi', + '蘦' => ' líng', + '蘾' => ' huài', + '蘳' => ' huī', + '蘽' => ' lěi', + '蘼' => ' mí', + '蘻' => ' jì', + '蘺' => ' lí', + '蘹' => ' huái', + '蘸' => ' zhàn', + '蘷' => ' kuí', + '蘶' => ' wèi', + '蘵' => ' zhī', + '蘴' => ' fēng', + '蘲' => ' léi', + '蘧' => ' qú', + '蘱' => ' lèi', + '蘰' => ' man', + '蘯' => ' dàng', + '蘮' => ' jì', + '蘭' => ' lán', + '蘬' => ' kuī', + '蘫' => ' hàn', + '蘪' => ' méi', + '蘩' => ' fán', + '蘨' => ' yáo', + '蝂' => ' bǎn', + '蝄' => ' wǎng', + '裣' => ' liǎn', + '衖' => ' xiàng', + '衠' => ' zhūn', + '衟' => ' dào', + '衞' => ' wèi', + '衝' => ' chōng', + '衜' => ' dào', + '衛' => ' wèi', + '衚' => ' hú', + '衙' => ' yá', + '衘' => ' xián', + '街' => ' jiē', + '衕' => ' tòng', + '衢' => ' qú', + '衔' => ' xián', + '術' => ' shù', + '衒' => ' xuàn', + '衑' => ' líng', + '衐' => ' qu', + '衏' => ' yuàn', + '衎' => ' kàn', + '衍' => ' yǎn', + '行' => ' xíng', + '衋' => ' xì', + '衡' => ' héng', + '衣' => ' yī', + '衉' => ' kā', + '衰' => ' shuāi', + '衺' => ' xié', + '衹' => ' zhǐ', + '衸' => ' jiè', + '衷' => ' zhōng', + '衶' => ' zhòng', + '衵' => ' yì', + '衴' => ' dǎn', + '衳' => ' zhōng', + '衲' => ' nà', + '衱' => ' jié', + '衯' => ' fēn', + '衤' => ' yī', + '衮' => ' gǔn', + '衭' => ' fū', + '衬' => ' chèn', + '衫' => ' shān', + '衪' => ' yí', + '衩' => ' chǎ', + '表' => ' biǎo', + '衧' => ' yú', + '衦' => ' gǎn', + '补' => ' bǔ', + '衊' => ' miè', + '衈' => ' èr', + '衼' => ' zhī', + '蠢' => ' chǔn', + '蠬' => ' lóng', + '蠫' => ' lì', + '蠪' => ' lóng', + '蠩' => ' zhū', + '蠨' => ' xiāo', + '蠧' => ' dù', + '蠦' => ' lú', + '蠥' => ' niè', + '蠤' => ' qiū', + '蠣' => ' lì', + '蠡' => ' lí', + '蠮' => ' yē', + '蠠' => ' mǐn', + '蠟' => ' là', + '蠞' => ' jié', + '蠝' => ' léi', + '蠜' => ' fán', + '蠛' => ' miè', + '蠚' => ' hē', + '蠙' => ' pín', + '蠘' => ' jié', + '蠗' => ' zhuó', + '蠭' => ' fēng', + '蠯' => ' bèng', + '衇' => ' mài', + '蠼' => ' qú', + '衆' => ' zhòng', + '衅' => ' xìn', + '衄' => ' nǜ', + '衃' => ' pēi', + '衂' => ' niù', + '衁' => ' huāng', + '血' => ' xuè', + '蠿' => ' zhuō', + '蠾' => ' zhú', + '蠽' => ' jié', + '蠻' => ' mán', + '蠰' => ' náng', + '蠺' => ' cán', + '蠹' => ' dù', + '蠸' => ' quán', + '蠷' => ' qú', + '蠶' => ' cán', + '蠵' => ' xī', + '蠴' => ' shu', + '蠳' => ' yīng', + '蠲' => ' juān', + '蠱' => ' gǔ', + '衻' => ' rán', + '衽' => ' rèn', + '蠕' => ' rú', + '袾' => ' zhū', + '裈' => ' kūn', + '裇' => ' xū', + '裆' => ' dāng', + '装' => ' zhuāng', + '裄' => ' xing', + '裃' => ' ka', + '裂' => ' liè', + '裁' => ' cái', + '裀' => ' yīn', + '袿' => ' guī', + '袽' => ' rú', + '裊' => ' niǎo', + '袼' => ' gē', + '袻' => ' ér', + '袺' => ' jié', + '袹' => ' bó', + '袸' => ' jiàn', + '袷' => ' jiá', + '袶' => ' jiàng', + '袵' => ' rèn', + '袴' => ' kù', + '袳' => ' chǐ', + '裉' => ' kèn', + '裋' => ' shù', + '袱' => ' fú', + '裘' => ' qiú', + '裢' => ' lián', + '裡' => ' lǐ', + '裠' => ' qún', + '裟' => ' shā', + '裞' => ' shuì', + '裝' => ' zhuāng', + '補' => ' bǔ', + '裛' => ' yì', + '裚' => ' jì', + '裙' => ' qún', + '裗' => ' liú', + '裌' => ' jiá', + '裖' => ' zhěn', + '裕' => ' yù', + '裔' => ' yì', + '裓' => ' gé', + '裒' => ' póu', + '裑' => ' shēn', + '裐' => ' juān', + '裏' => ' lǐ', + '裎' => ' chéng', + '裍' => ' kǔn', + '袲' => ' chǐ', + '袰' => ' bō', + '衾' => ' qīn', + '袊' => ' lǐng', + '袔' => ' hè', + '袓' => ' jù', + '袒' => ' tǎn', + '袑' => ' shào', + '袐' => ' bì', + '袏' => ' zuò', + '袎' => ' yào', + '袍' => ' páo', + '袌' => ' bào', + '袋' => ' dài', + '袉' => ' tuó', + '袖' => ' xiù', + '袈' => ' jiā', + '袇' => ' rán', + '袆' => ' huī', + '袅' => ' niǎo', + '袄' => ' ǎo', + '袃' => ' chài', + '袂' => ' mèi', + '袁' => ' yuán', + '袀' => ' jūn', + '衿' => ' jīn', + '袕' => ' xué', + '袗' => ' zhěn', + '袯' => ' bó', + '袤' => ' mào', + '袮' => ' ni', + '袭' => ' xí', + '袬' => ' gǔn', + '被' => ' bèi', + '袪' => ' qū', + '袩' => ' zhé', + '袨' => ' xuàn', + '袧' => ' gōu', + '袦' => ' nà', + '袥' => ' tuō', + '袣' => ' yì', + '袘' => ' yí', + '袢' => ' pàn', + '袡' => ' rán', + '袠' => ' zhì', + '袟' => ' zhì', + '袞' => ' gǔn', + '袝' => ' fù', + '袜' => ' wà', + '袛' => ' dī', + '袚' => ' bō', + '袙' => ' pà', + '蠖' => ' huò', + '蠔' => ' háo', + '蝅' => ' cán', + '螅' => ' xī', + '螏' => ' jí', + '螎' => ' róng', + '融' => ' róng', + '螌' => ' bān', + '螋' => ' sōu', + '螊' => ' lián', + '螉' => ' wēng', + '螈' => ' yuán', + '螇' => ' xī', + '螆' => ' cì', + '螄' => ' sī', + '螑' => ' xiù', + '螃' => ' páng', + '螂' => ' láng', + '螁' => ' ban', + '螀' => ' jiāng', + '蝿' => ' yíng', + '蝾' => ' róng', + '蝽' => ' chūn', + '蝼' => ' lóu', + '蝻' => ' nǎn', + '蝺' => ' qǔ', + '螐' => ' wū', + '螒' => ' hàn', + '蝸' => ' wō', + '螟' => ' míng', + '螩' => ' tiao', + '螨' => ' mǎn', + '螧' => ' qi', + '螦' => ' sao', + '螥' => ' cāng', + '螤' => ' zhōng', + '螣' => ' tè', + '螢' => ' yíng', + '螡' => ' wén', + '螠' => ' yì', + '螞' => ' mǎ', + '螓' => ' qín', + '螝' => ' guī', + '螜' => ' hú', + '螛' => ' hé', + '螚' => ' nài', + '螙' => ' dù', + '螘' => ' yǐ', + '螗' => ' táng', + '螖' => ' huá', + '螕' => ' bī', + '螔' => ' yí', + '蝹' => ' yūn', + '蝷' => ' lì', + '螫' => ' shì', + '蝑' => ' xū', + '蝛' => ' wēi', + '蝚' => ' róu', + '蝙' => ' biān', + '蝘' => ' yǎn', + '蝗' => ' huáng', + '蝖' => ' xuān', + '蝕' => ' shí', + '蝔' => ' jiē', + '蝓' => ' yú', + '蝒' => ' mián', + '蝐' => ' mào', + '蝝' => ' yuán', + '蝏' => ' tíng', + '蝎' => ' xiē', + '蝍' => ' jié', + '蝌' => ' kē', + '蝋' => ' là', + '蝊' => ' dìng', + '蝉' => ' chán', + '蝈' => ' guō', + '蝇' => ' yíng', + '蝆' => ' yǎng', + '蝜' => ' fù', + '蝞' => ' mèi', + '蝶' => ' dié', + '蝫' => ' zhū', + '蝵' => ' qiū', + '蝴' => ' hú', + '蝳' => ' dú', + '蝲' => ' là', + '蝱' => ' méng', + '蝰' => ' kuí', + '蝯' => ' yuán', + '蝮' => ' fù', + '蝭' => ' tí', + '蝬' => ' zōng', + '蝪' => ' tāng', + '蝟' => ' wèi', + '蝩' => ' chóng', + '蝨' => ' shī', + '蝧' => ' yīng', + '蝦' => ' xiā', + '蝥' => ' máo', + '蝤' => ' qiú', + '蝣' => ' yóu', + '蝢' => ' xié', + '蝡' => ' rú', + '蝠' => ' fú', + '螪' => ' shāng', + '螬' => ' cáo', + '蠓' => ' měng', + '蟮' => ' shàn', + '蟸' => ' lǐ', + '蟷' => ' dāng', + '蟶' => ' chēng', + '蟵' => ' chu', + '蟴' => ' sī', + '蟳' => ' xún', + '蟲' => ' chóng', + '蟱' => ' wú', + '蟰' => ' xiāo', + '蟯' => ' náo', + '蟭' => ' jiāo', + '蟺' => ' shàn', + '蟬' => ' chán', + '蟫' => ' yín', + '蟪' => ' huì', + '蟩' => ' jué', + '蟨' => ' jué', + '蟧' => ' láo', + '蟦' => ' féi', + '蟥' => ' huáng', + '蟤' => ' zhuān', + '蟣' => ' jǐ', + '蟹' => ' xiè', + '蟻' => ' yǐ', + '蟡' => ' guǐ', + '蠈' => ' zéi', + '蠒' => ' jiǎn', + '蠑' => ' róng', + '蠐' => ' qí', + '蠏' => ' xiè', + '蠎' => ' mǎng', + '蠍' => ' xiē', + '蠌' => ' zé', + '蠋' => ' zhú', + '蠊' => ' lián', + '蠉' => ' xuān', + '蠇' => ' lì', + '蟼' => ' jǐng', + '蠆' => ' chài', + '蠅' => ' yíng', + '蠄' => ' qín', + '蠃' => ' luǒ', + '蠂' => ' shè', + '蠁' => ' xiǎng', + '蠀' => ' cī', + '蟿' => ' qì', + '蟾' => ' chán', + '蟽' => ' dá', + '蟢' => ' xǐ', + '蟠' => ' pán', + '螭' => ' chī', + '螹' => ' jiàn', + '蟃' => ' wàn', + '蟂' => ' xiāo', + '蟁' => ' wén', + '蟀' => ' shuài', + '螿' => ' jiāng', + '螾' => ' yǐn', + '螽' => ' zhōng', + '螼' => ' qǐn', + '螻' => ' lóu', + '螺' => ' luó', + '螸' => ' yú', + '蟅' => ' zhè', + '螷' => ' pí', + '螶' => ' qú', + '螵' => ' piāo', + '螴' => ' chén', + '螳' => ' táng', + '螲' => ' zhì', + '螱' => ' wèi', + '螰' => ' lù', + '螯' => ' áo', + '螮' => ' dì', + '蟄' => ' zhé', + '蟆' => ' má', + '蟟' => ' liáo', + '蟔' => ' mò', + '蟞' => ' biē', + '蟝' => ' qú', + '蟜' => ' jiǎo', + '蟛' => ' péng', + '蟚' => ' péng', + '蟙' => ' zhí', + '蟘' => ' tè', + '蟗' => ' qiū', + '蟖' => ' sī', + '蟕' => ' zuī', + '蟓' => ' xiàng', + '蟇' => ' má', + '蟒' => ' mǎng', + '蟑' => ' zhāng', + '蟐' => ' chang', + '蟏' => ' xiāo', + '蟎' => ' mǎn', + '蟍' => ' lí', + '蟌' => ' cōng', + '蟋' => ' xī', + '蟊' => ' máo', + '蟉' => ' liú', + '蟈' => ' guō', + '谣' => ' yáo', + '谥' => ' shì', + '銥' => ' yī', + '遷' => ' qiān', + '邁' => ' mài', + '邀' => ' yāo', + '避' => ' bì', + '遾' => ' shì', + '遽' => ' jù', + '遼' => ' liáo', + '遻' => ' wù', + '遺' => ' yí', + '遹' => ' yù', + '選' => ' xuǎn', + '遶' => ' rào', + '邃' => ' suì', + '遵' => ' zūn', + '遴' => ' lín', + '遳' => ' cuō', + '遲' => ' chí', + '遱' => ' lóu', + '遰' => ' dì', + '遯' => ' dùn', + '遮' => ' zhē', + '遭' => ' zāo', + '遬' => ' sù', + '邂' => ' xiè', + '還' => ' hái', + '遪' => ' cà', + '邑' => ' yì', + '邛' => ' qióng', + '邚' => ' rú', + '邙' => ' máng', + '邘' => ' yú', + '邗' => ' hán', + '邖' => ' shān', + '邕' => ' yōng', + '邔' => ' qǐ', + '邓' => ' dèng', + '邒' => ' tíng', + '邐' => ' lǐ', + '邅' => ' zhān', + '邏' => ' luó', + '邎' => ' yáo', + '邍' => ' yuán', + '邌' => ' lí', + '邋' => ' lā', + '邊' => ' biān', + '邉' => ' biān', + '邈' => ' miǎo', + '邇' => ' ěr', + '邆' => ' téng', + '遫' => ' chì', + '適' => ' shì', + '邝' => ' kuàng', + '遃' => ' yǎn', + '遍' => ' biàn', + '遌' => ' è', + '運' => ' yùn', + '遊' => ' yóu', + '遉' => ' zhēn', + '遈' => ' shí', + '遇' => ' yù', + '遆' => ' tí', + '遅' => ' chí', + '遄' => ' chuán', + '遂' => ' suì', + '遏' => ' è', + '遁' => ' dùn', + '遀' => ' suí', + '逿' => ' dàng', + '逾' => ' yú', + '逽' => ' nuò', + '逼' => ' bī', + '逻' => ' luó', + '逺' => ' yuǎn', + '逹' => ' dá', + '逸' => ' yì', + '過' => ' guò', + '遐' => ' xiá', + '遨' => ' áo', + '遝' => ' tà', + '遧' => ' zhāng', + '遦' => ' guàn', + '遥' => ' yáo', + '遤' => ' ma', + '遣' => ' qiǎn', + '遢' => ' tà', + '遡' => ' sù', + '遠' => ' yuǎn', + '遟' => ' chí', + '遞' => ' dì', + '遜' => ' xùn', + '遑' => ' huáng', + '遛' => ' liú', + '遚' => ' chòu', + '遙' => ' yáo', + '遘' => ' gòu', + '遗' => ' yí', + '遖' => ' nan', + '違' => ' wéi', + '達' => ' dá', + '道' => ' dào', + '遒' => ' qiú', + '邜' => ' wan', + '邞' => ' fū', + '逶' => ' wēi', + '郟' => ' jiá', + '郩' => ' xiáo', + '部' => ' bù', + '郧' => ' yún', + '郦' => ' lì', + '郥' => ' bèi', + '郤' => ' xì', + '郣' => ' bó', + '郢' => ' yǐng', + '郡' => ' jùn', + '郠' => ' gěng', + '郞' => ' láng', + '郫' => ' pí', + '郝' => ' hǎo', + '郜' => ' gào', + '郛' => ' fú', + '郚' => ' wú', + '郙' => ' fǔ', + '郘' => ' lǘ', + '郗' => ' xī', + '郖' => ' dòu', + '郕' => ' chéng', + '郔' => ' yán', + '郪' => ' qī', + '郬' => ' qīng', + '郒' => ' lang', + '郹' => ' jú', + '鄃' => ' shū', + '鄂' => ' è', + '鄁' => ' bèi', + '鄀' => ' ruò', + '郿' => ' méi', + '郾' => ' yǎn', + '都' => ' dōu', + '郼' => ' yī', + '郻' => ' qiāo', + '郺' => ' yōng', + '郸' => ' dān', + '郭' => ' guō', + '郷' => ' xiāng', + '郶' => ' bù', + '郵' => ' yóu', + '郴' => ' chēn', + '郳' => ' ní', + '郲' => ' lái', + '郱' => ' píng', + '郰' => ' zōu', + '郯' => ' tán', + '郮' => ' zhōu', + '郓' => ' yùn', + '郑' => ' zhèng', + '邟' => ' kàng', + '邫' => ' bāng', + '邵' => ' shào', + '邴' => ' bǐng', + '邳' => ' pī', + '邲' => ' bì', + '邱' => ' qiū', + '邰' => ' tái', + '邯' => ' hán', + '邮' => ' yóu', + '邭' => ' jù', + '邬' => ' wū', + '邪' => ' xié', + '邷' => ' wǎ', + '邩' => ' huǒ', + '邨' => ' cūn', + '邧' => ' yuán', + '邦' => ' bāng', + '邥' => ' shěn', + '邤' => ' xīn', + '那' => ' nà', + '邢' => ' xíng', + '邡' => ' fāng', + '邠' => ' bīn', + '邶' => ' bèi', + '邸' => ' dǐ', + '郐' => ' kuài', + '郅' => ' zhì', + '郏' => ' jiá', + '郎' => ' láng', + '郍' => ' nuó', + '郌' => ' guī', + '郋' => ' xí', + '郊' => ' jiāo', + '郉' => ' xíng', + '郈' => ' hòu', + '郇' => ' huán', + '郆' => ' jí', + '郄' => ' qiè', + '邹' => ' zōu', + '郃' => ' hé', + '郂' => ' gāi', + '郁' => ' yù', + '郀' => ' kū', + '邿' => ' shī', + '邾' => ' zhū', + '邽' => ' guī', + '邼' => ' kuāng', + '邻' => ' lín', + '邺' => ' yè', + '逷' => ' tì', + '逵' => ' kuí', + '鄅' => ' yǔ', + '辧' => ' biàn', + '辱' => ' rǔ', + '辰' => ' chén', + '辯' => ' biàn', + '辮' => ' biàn', + '辭' => ' cí', + '辬' => ' bān', + '辫' => ' biàn', + '辪' => ' xuē', + '辩' => ' biàn', + '辨' => ' biàn', + '辦' => ' bàn', + '辳' => ' nóng', + '辥' => ' xuē', + '辤' => ' cí', + '辣' => ' là', + '辢' => ' là', + '辡' => ' biàn', + '辠' => ' zuì', + '辟' => ' pì', + '辞' => ' cí', + '辝' => ' cí', + '辜' => ' gū', + '農' => ' nóng', + '辴' => ' chǎn', + '辚' => ' lín', + '迁' => ' qiān', + '迋' => ' wàng', + '迊' => ' zā', + '迉' => ' qī', + '迈' => ' mài', + '过' => ' guò', + '迆' => ' yí', + '迅' => ' xùn', + '迄' => ' qì', + '迃' => ' yū', + '迂' => ' yū', + '迀' => ' gān', + '辵' => ' chuò', + '辿' => ' chān', + '达' => ' dá', + '辽' => ' liáo', + '込' => ' ru', + '辻' => ' shí', + '辺' => ' biān', + '边' => ' biān', + '辸' => ' réng', + '辷' => ' yi', + '辶' => ' chuò', + '辛' => ' xīn', + '辙' => ' zhé', + '迍' => ' zhūn', + '轳' => ' lú', + '载' => ' zài', + '轼' => ' shì', + '轻' => ' qīng', + '轺' => ' yáo', + '轹' => ' lì', + '轸' => ' zhěn', + '轷' => ' hū', + '轶' => ' yì', + '轵' => ' zhǐ', + '轴' => ' zhóu', + '轲' => ' kē', + '轿' => ' jiào', + '轱' => ' gū', + '轰' => ' hōng', + '软' => ' ruǎn', + '轮' => ' lún', + '轭' => ' è', + '转' => ' zhuǎn', + '轫' => ' rèn', + '轪' => ' dài', + '轩' => ' xuān', + '轨' => ' guǐ', + '轾' => ' zhì', + '辀' => ' zhōu', + '辘' => ' lù', + '辍' => ' chuò', + '辗' => ' niǎn', + '辖' => ' xiá', + '辕' => ' yuán', + '辔' => ' pèi', + '输' => ' shū', + '辒' => ' wēn', + '辑' => ' jí', + '辐' => ' fú', + '辏' => ' còu', + '辎' => ' zī', + '辌' => ' liáng', + '辁' => ' quán', + '辋' => ' wǎng', + '辊' => ' gǔn', + '辉' => ' huī', + '辈' => ' bèi', + '辇' => ' niǎn', + '辆' => ' liàng', + '辅' => ' fǔ', + '辄' => ' zhé', + '较' => ' jiào', + '辂' => ' lù', + '迌' => ' tù', + '迎' => ' yíng', + '逴' => ' chuō', + '透' => ' tòu', + '這' => ' zhè', + '逘' => ' yǐ', + '逗' => ' dòu', + '逖' => ' tì', + '逕' => ' jìng', + '途' => ' tú', + '逓' => ' dì', + '递' => ' dì', + '逑' => ' qiú', + '逐' => ' zhú', + '逎' => ' qiú', + '逛' => ' guàng', + '逍' => ' xiāo', + '逌' => ' yōu', + '逋' => ' bū', + '逊' => ' xùn', + '选' => ' xuǎn', + '逈' => ' jiǒng', + '逇' => ' dùn', + '逆' => ' nì', + '逅' => ' hòu', + '逄' => ' páng', + '通' => ' tōng', + '逜' => ' wù', + '适' => ' shì', + '逩' => ' bèn', + '逳' => ' yù', + '進' => ' jìn', + '週' => ' zhōu', + '逰' => ' yóu', + '逯' => ' lù', + '逮' => ' dǎi', + '逭' => ' huàn', + '逬' => ' bèng', + '逫' => ' jué', + '逪' => ' cuò', + '逨' => ' lái', + '逝' => ' shì', + '逧' => ' gu', + '逦' => ' lǐ', + '逥' => ' huí', + '逤' => ' suò', + '連' => ' lián', + '逢' => ' féng', + '逡' => ' qūn', + '造' => ' zào', + '速' => ' sù', + '逞' => ' chěng', + '逃' => ' táo', + '送' => ' sòng', + '迏' => ' tì', + '进' => ' jìn', + '迥' => ' jiǒng', + '迤' => ' yí', + '迣' => ' zhì', + '迢' => ' tiáo', + '迡' => ' nì', + '迠' => ' chè', + '迟' => ' chí', + '连' => ' lián', + '违' => ' wéi', + '远' => ' yuǎn', + '迚' => ' zhong', + '迧' => ' chén', + '这' => ' zhè', + '还' => ' hái', + '迗' => ' é', + '迖' => ' dá', + '迕' => ' wù', + '返' => ' fǎn', + '迓' => ' yà', + '迒' => ' háng', + '近' => ' jìn', + '运' => ' yùn', + '迦' => ' jiā', + '迨' => ' dài', + '退' => ' tuì', + '迵' => ' dòng', + '迿' => ' xùn', + '迾' => ' liè', + '追' => ' zhuī', + '迼' => ' jié', + '迻' => ' yí', + '迺' => ' nǎi', + '迹' => ' jī', + '迸' => ' bèng', + '迷' => ' mí', + '迶' => ' yòu', + '迴' => ' huí', + '迩' => ' ěr', + '迳' => ' jìng', + '迲' => ' qu', + '迱' => ' tuó', + '述' => ' shù', + '迯' => ' táo', + '迮' => ' zé', + '迭' => ' dié', + '迬' => ' zhù', + '迫' => ' pò', + '迪' => ' dí', + '鄄' => ' juàn', + '鄆' => ' yùn', + '车' => ' chē', + '鈘' => ' jǐ', + '鈢' => ' xǐ', + '鈡' => ' zhōng', + '鈠' => ' yì', + '鈟' => ' shī', + '鈞' => ' jūn', + '鈝' => ' yín', + '鈜' => ' hóng', + '鈛' => ' guō', + '鈚' => ' pī', + '鈙' => ' qín', + '鈗' => ' yǔn', + '鈤' => ' rì', + '鈖' => ' fēn', + '鈕' => ' niǔ', + '鈔' => ' chāo', + '鈓' => ' rén', + '鈒' => ' sà', + '鈑' => ' bǎn', + '鈐' => ' qián', + '鈏' => ' yǐn', + '鈎' => ' gōu', + '鈍' => ' dùn', + '鈣' => ' gài', + '鈥' => ' huǒ', + '鈋' => ' é', + '鈲' => ' gū', + '鈼' => ' zuó', + '鈻' => ' sì', + '鈺' => ' yù', + '鈹' => ' pī', + '鈸' => ' bó', + '鈷' => ' gǔ', + '鈶' => ' sì', + '鈵' => ' bǐng', + '鈴' => ' líng', + '鈳' => ' kē', + '鈱' => ' mín', + '鈦' => ' tài', + '鈰' => ' shì', + '鈯' => ' tú', + '鈮' => ' nǐ', + '鈭' => ' zī', + '鈬' => ' duó', + '鈫' => ' wen', + '鈪' => ' è', + '鈩' => ' lu', + '鈨' => ' yuan', + '鈧' => ' kàng', + '鈌' => ' jué', + '鈊' => ' xīn', + '鈾' => ' yóu', + '釤' => ' shàn', + '釮' => ' qí', + '釭' => ' gāng', + '釬' => ' hàn', + '釫' => ' huá', + '釪' => ' huá', + '釩' => ' fǎn', + '釨' => ' zǐ', + '釧' => ' chuàn', + '釦' => ' kòu', + '釥' => ' qiǎo', + '釣' => ' diào', + '釰' => ' rì', + '釢' => ' nǎi', + '釡' => ' fǔ', + '釠' => ' luàn', + '釟' => ' bā', + '釞' => ' zhí', + '針' => ' zhēn', + '釜' => ' fǔ', + '釛' => ' bā', + '釚' => ' qiú', + '釙' => ' pò', + '釯' => ' máng', + '釱' => ' dì', + '鈉' => ' nà', + '釾' => ' yé', + '鈈' => ' pī', + '鈇' => ' fū', + '鈆' => ' qiān', + '鈅' => ' yuè', + '鈄' => ' dǒu', + '鈃' => ' xíng', + '鈂' => ' chén', + '鈁' => ' fāng', + '鈀' => ' bǎ', + '釿' => ' jīn', + '釽' => ' pì', + '釲' => ' sì', + '釼' => ' jiàn', + '釻' => ' qiu', + '釺' => ' qiān', + '釹' => ' nǚ', + '釸' => ' xī', + '釷' => ' tǔ', + '釶' => ' shī', + '釵' => ' chāi', + '釴' => ' yì', + '釳' => ' xì', + '鈽' => ' bū', + '鈿' => ' tián', + '釗' => ' zhāo', + '銀' => ' yín', + '銊' => ' xù', + '銉' => ' yù', + '銈' => ' jī', + '銇' => ' lèi', + '銆' => ' mò', + '銅' => ' tóng', + '銄' => ' xiǎng', + '銃' => ' chòng', + '銂' => ' zhōu', + '銁' => ' jūn', + '鉿' => ' jiā', + '銌' => ' zùn', + '鉾' => ' móu', + '鉽' => ' shì', + '鉼' => ' bǐng', + '鉻' => ' luò', + '鉺' => ' èr', + '鉹' => ' chǐ', + '鉸' => ' jiǎo', + '鉷' => ' hóng', + '鉶' => ' xíng', + '鉵' => ' tóng', + '銋' => ' rén', + '銍' => ' zhì', + '鉳' => ' běi', + '銚' => ' yáo', + '銤' => ' mǐ', + '銣' => ' rú', + '銢' => ' pǐ', + '銡' => ' jí', + '銠' => ' lǎo', + '銟' => ' chā', + '銞' => ' jūn', + '銝' => ' xiū', + '銜' => ' xián', + '銛' => ' xiān', + '銙' => ' kuǎ', + '銎' => ' qióng', + '銘' => ' míng', + '銗' => ' xiàng', + '銖' => ' zhū', + '銕' => ' tiě', + '銔' => ' pī', + '銓' => ' quán', + '銒' => ' xíng', + '銑' => ' xiǎn', + '銐' => ' chì', + '銏' => ' shàn', + '鉴' => ' jiàn', + '鉲' => ' kǎ', + '鉀' => ' jiǎ', + '鉌' => ' hé', + '鉖' => ' tóng', + '鉕' => ' pō', + '鉔' => ' zā', + '鉓' => ' chì', + '鉒' => ' zhù', + '鉑' => ' bó', + '鉐' => ' shí', + '鉏' => ' chú', + '鉎' => ' shēng', + '鉍' => ' bì', + '鉋' => ' bào', + '鉘' => ' fú', + '鉊' => ' zhāo', + '鉉' => ' xuàn', + '鉈' => ' shī', + '鉇' => ' shī', + '鉆' => ' chān', + '鉅' => ' jù', + '鉄' => ' zhí', + '鉃' => ' shì', + '鉂' => ' shǐ', + '鉁' => ' zhēn', + '鉗' => ' qián', + '鉙' => ' zhǎi', + '鉱' => ' kuàng', + '鉦' => ' zhēng', + '鉰' => ' sī', + '鉯' => ' yǐ', + '鉮' => ' huán', + '鉭' => ' tǎn', + '鉬' => ' mù', + '鉫' => ' jiā', + '鉪' => ' dì', + '鉩' => ' xǐ', + '鉨' => ' xǐ', + '鉧' => ' mǔ', + '鉥' => ' shù', + '鉚' => ' liǔ', + '鉤' => ' gōu', + '鉣' => ' jié', + '鉢' => ' bō', + '鉡' => ' bàn', + '鉠' => ' yāng', + '鉟' => ' pī', + '鉞' => ' yuè', + '鉝' => ' lì', + '鉜' => ' fú', + '鉛' => ' qiān', + '釘' => ' dīng', + '釖' => ' dāo', + '鄇' => ' hóu', + '酇' => ' zàn', + '酑' => ' yú', + '酐' => ' gān', + '酏' => ' yǐ', + '酎' => ' zhòu', + '配' => ' pèi', + '酌' => ' zhuó', + '酋' => ' qiú', + '酊' => ' dīng', + '酉' => ' yǒu', + '酈' => ' lì', + '酆' => ' fēng', + '酓' => ' yǎn', + '酅' => ' xī', + '酄' => ' huān', + '酃' => ' líng', + '酂' => ' cuó', + '酁' => ' chán', + '酀' => ' yàn', + '鄿' => ' jī', + '鄾' => ' yōu', + '鄽' => ' chán', + '鄼' => ' zàn', + '酒' => ' jiǔ', + '酔' => ' zuì', + '鄺' => ' kuàng', + '酡' => ' tuó', + '酫' => ' chuò', + '酪' => ' lào', + '酩' => ' mǐng', + '酨' => ' zài', + '酧' => ' chóu', + '酦' => ' fā', + '酥' => ' sū', + '酤' => ' gū', + '酣' => ' hān', + '酢' => ' cù', + '酠' => ' qiǎ', + '酕' => ' máo', + '酟' => ' tiān', + '酞' => ' tài', + '酝' => ' yùn', + '酜' => ' fu', + '酛' => ' yuan', + '酚' => ' fēn', + '酙' => ' zhēn', + '酘' => ' dòu', + '酗' => ' xù', + '酖' => ' zhèn', + '鄻' => ' liǎn', + '鄹' => ' zōu', + '酭' => ' yòu', + '鄓' => ' yè', + '鄝' => ' liǎo', + '鄜' => ' fū', + '鄛' => ' cháo', + '鄚' => ' mào', + '鄙' => ' bǐ', + '鄘' => ' yōng', + '鄗' => ' hào', + '鄖' => ' yún', + '鄕' => ' xiāng', + '鄔' => ' wū', + '鄒' => ' zōu', + '鄟' => ' zhuān', + '鄑' => ' zī', + '鄐' => ' chù', + '鄏' => ' rǔ', + '鄎' => ' xī', + '鄍' => ' míng', + '鄌' => ' táng', + '鄋' => ' sōu', + '鄊' => ' xiāng', + '鄉' => ' xiāng', + '鄈' => ' kuí', + '鄞' => ' yín', + '鄠' => ' hù', + '鄸' => ' méng', + '鄭' => ' zhèng', + '鄷' => ' fēng', + '鄶' => ' kuài', + '鄵' => ' cào', + '鄴' => ' yè', + '鄳' => ' méng', + '鄲' => ' dān', + '鄱' => ' pó', + '鄰' => ' lín', + '鄯' => ' shàn', + '鄮' => ' mào', + '鄬' => ' wéi', + '鄡' => ' qiāo', + '鄫' => ' zēng', + '鄪' => ' bì', + '鄩' => ' xún', + '鄨' => ' bì', + '鄧' => ' dèng', + '鄦' => ' xǔ', + '鄥' => ' qiāo', + '鄤' => ' màn', + '鄣' => ' zhāng', + '鄢' => ' yān', + '酬' => ' chóu', + '酮' => ' tóng', + '釕' => ' liǎo', + '醰' => ' tán', + '醺' => ' xūn', + '醹' => ' rú', + '醸' => ' niàng', + '醷' => ' yì', + '醶' => ' yàn', + '醵' => ' jù', + '醴' => ' lǐ', + '醳' => ' yì', + '醲' => ' nóng', + '醱' => ' fā', + '醯' => ' xī', + '醼' => ' yàn', + '醮' => ' jiào', + '醭' => ' bú', + '醬' => ' jiàng', + '醫' => ' yī', + '醪' => ' láo', + '醩' => ' zāo', + '醨' => ' lí', + '醧' => ' yù', + '醦' => ' chěn', + '醥' => ' piǎo', + '醻' => ' chóu', + '醽' => ' líng', + '醣' => ' táng', + '释' => ' shì', + '釔' => ' yǐ', + '釓' => ' qiú', + '釒' => ' jīn', + '金' => ' jīn', + '釐' => ' lí', + '量' => ' liàng', + '野' => ' yě', + '重' => ' zhòng', + '里' => ' lǐ', + '釋' => ' shì', + '釉' => ' yòu', + '醾' => ' mí', + '釈' => ' shì', + '采' => ' cǎi', + '釆' => ' biàn', + '釅' => ' yàn', + '釄' => ' mí', + '釃' => ' shāi', + '釂' => ' jiào', + '釁' => ' xìn', + '釀' => ' niàng', + '醿' => ' mí', + '醤' => ' jiàng', + '醢' => ' hǎi', + '酯' => ' zhǐ', + '酻' => ' zuì', + '醅' => ' pēi', + '醄' => ' táo', + '醃' => ' yān', + '醂' => ' lǎn', + '醁' => ' lù', + '醀' => ' wéi', + '酿' => ' niàng', + '酾' => ' shāi', + '酽' => ' yàn', + '酼' => ' hǎi', + '酺' => ' pú', + '醇' => ' chún', + '酹' => ' lèi', + '酸' => ' suān', + '酷' => ' kù', + '酶' => ' méi', + '酵' => ' jiào', + '酴' => ' tú', + '酳' => ' yìn', + '酲' => ' chéng', + '酱' => ' jiàng', + '酰' => ' xiān', + '醆' => ' zhǎn', + '醈' => ' tán', + '醡' => ' zhà', + '醖' => ' yùn', + '醠' => ' àng', + '醟' => ' yòng', + '醞' => ' yùn', + '醝' => ' cuō', + '醜' => ' chǒu', + '醛' => ' quán', + '醚' => ' mí', + '醙' => ' sōu', + '醘' => ' kē', + '醗' => ' pò', + '醕' => ' chún', + '醉' => ' zuì', + '醔' => ' qiú', + '醓' => ' tǎn', + '醒' => ' xǐng', + '醑' => ' xǔ', + '醐' => ' hú', + '醏' => ' dū', + '醎' => ' xián', + '醍' => ' tí', + '醌' => ' kūn', + '醋' => ' cù', + '醊' => ' zhuì', + '轧' => ' yà', + '轥' => ' lìn', + '谦' => ' qiān', + '贶' => ' kuàng', + '赀' => ' zī', + '贿' => ' huì', + '贾' => ' jiǎ', + '贽' => ' zhì', + '贼' => ' zéi', + '贻' => ' yí', + '贺' => ' hè', + '费' => ' fèi', + '贸' => ' mào', + '贷' => ' dài', + '贵' => ' guì', + '赂' => ' lù', + '贴' => ' tiē', + '贳' => ' shì', + '贲' => ' bēn', + '贱' => ' jiàn', + '贰' => ' èr', + '贯' => ' guàn', + '贮' => ' zhù', + '购' => ' gòu', + '贬' => ' biǎn', + '贫' => ' pín', + '赁' => ' lìn', + '赃' => ' zāng', + '贩' => ' fàn', + '赐' => ' cì', + '赚' => ' zhuàn', + '赙' => ' fù', + '赘' => ' zhuì', + '赗' => ' fèng', + '赖' => ' lài', + '赕' => ' dǎn', + '赔' => ' péi', + '赓' => ' gēng', + '赒' => ' zhōu', + '赑' => ' bì', + '赏' => ' shǎng', + '资' => ' zī', + '赎' => ' shú', + '赍' => ' jī', + '赌' => ' dǔ', + '赋' => ' fù', + '赊' => ' shē', + '赉' => ' lài', + '赈' => ' zhèn', + '赇' => ' qiú', + '赆' => ' jìn', + '赅' => ' gāi', + '贪' => ' tān', + '质' => ' zhì', + '赜' => ' zé', + '贂' => ' chěn', + '贌' => ' pu', + '贋' => ' yàn', + '贊' => ' zàn', + '贉' => ' dàn', + '贈' => ' zèng', + '贇' => ' yūn', + '贆' => ' biāo', + '贅' => ' zhuì', + '贄' => ' zhì', + '贃' => ' wàn', + '贁' => ' bài', + '贎' => ' wàn', + '贀' => ' yì', + '賿' => ' liáo', + '賾' => ' zé', + '賽' => ' sài', + '購' => ' gòu', + '賻' => ' fù', + '賺' => ' zhuàn', + '賹' => ' yì', + '賸' => ' shèng', + '賷' => ' jī', + '贍' => ' shàn', + '贏' => ' yíng', + '货' => ' huò', + '贜' => ' zāng', + '账' => ' zhàng', + '败' => ' bài', + '贤' => ' xián', + '责' => ' zé', + '财' => ' cái', + '贡' => ' gòng', + '贠' => ' yuán', + '负' => ' fù', + '贞' => ' zhēn', + '贝' => ' bèi', + '贛' => ' gàn', + '贐' => ' jìn', + '贚' => ' lòng', + '贙' => ' xuàn', + '贘' => ' shǎng', + '贗' => ' yàn', + '贖' => ' shú', + '贕' => ' dú', + '贔' => ' bì', + '贓' => ' zāng', + '贒' => ' xián', + '贑' => ' gàn', + '赛' => ' sài', + '赝' => ' yàn', + '賵' => ' fèng', + '趞' => ' què', + '趨' => ' qū', + '趧' => ' tí', + '趦' => ' zī', + '趥' => ' qiū', + '趤' => ' dàng', + '趣' => ' qù', + '趢' => ' lù', + '趡' => ' cuǐ', + '趠' => ' chuò', + '趟' => ' tàng', + '趝' => ' jiàn', + '趪' => ' huáng', + '趜' => ' jú', + '趛' => ' yǐn', + '趚' => ' sù', + '趙' => ' zhào', + '趘' => ' xí', + '趗' => ' cù', + '趖' => ' suō', + '趕' => ' gǎn', + '趔' => ' liè', + '趓' => ' duǒ', + '趩' => ' chì', + '趫' => ' qiáo', + '趑' => ' zī', + '趸' => ' dǔn', + '跂' => ' qí', + '跁' => ' bà', + '跀' => ' yuè', + '趿' => ' tā', + '趾' => ' zhǐ', + '趽' => ' fàng', + '趼' => ' jiǎn', + '趻' => ' chěn', + '趺' => ' fū', + '趹' => ' jué', + '趷' => ' kē', + '趬' => ' qiāo', + '趶' => ' kù', + '趵' => ' bào', + '趴' => ' pā', + '足' => ' zú', + '趲' => ' zǎn', + '趱' => ' zǎn', + '趰' => ' ěr', + '趯' => ' tì', + '趮' => ' zào', + '趭' => ' jiào', + '趒' => ' tiáo', + '趐' => ' xuè', + '赞' => ' zàn', + '赪' => ' chēng', + '赴' => ' fù', + '赳' => ' jiū', + '赲' => ' lì', + '赱' => ' zǒu', + '走' => ' zǒu', + '赯' => ' táng', + '赮' => ' xiá', + '赭' => ' zhě', + '赬' => ' chēng', + '赫' => ' hè', + '赩' => ' xì', + '赶' => ' gǎn', + '赨' => ' tóng', + '赧' => ' nǎn', + '赦' => ' shè', + '赥' => ' xī', + '赤' => ' chì', + '赣' => ' gàn', + '赢' => ' yíng', + '赡' => ' shàn', + '赠' => ' zèng', + '赟' => ' yūn', + '赵' => ' zhào', + '起' => ' qǐ', + '趏' => ' guā', + '趄' => ' jū', + '趎' => ' chú', + '趍' => ' chí', + '趌' => ' jí', + '趋' => ' qū', + '越' => ' yuè', + '趉' => ' jué', + '趈' => ' zhān', + '趇' => ' xì', + '趆' => ' dī', + '超' => ' chāo', + '趃' => ' dié', + '赸' => ' shàn', + '趂' => ' chèn', + '趁' => ' chèn', + '趀' => ' cī', + '赿' => ' chí', + '赾' => ' qǐn', + '赽' => ' jué', + '赼' => ' cī', + '赻' => ' xiǎn', + '赺' => ' yǐn', + '赹' => ' qióng', + '賶' => ' càng', + '賴' => ' lài', + '跄' => ' qiāng', + '豦' => ' jù', + '豰' => ' bó', + '豯' => ' xī', + '豮' => ' fén', + '豭' => ' jiā', + '豬' => ' zhū', + '豫' => ' yù', + '豪' => ' háo', + '豩' => ' bīn', + '豨' => ' xī', + '豧' => ' fū', + '豥' => ' gāi', + '豲' => ' huán', + '豤' => ' kěn', + '豣' => ' jiān', + '豢' => ' huàn', + '象' => ' xiàng', + '豠' => ' chú', + '豟' => ' è', + '豞' => ' hòu', + '豝' => ' bā', + '豜' => ' jiān', + '豛' => ' yì', + '豱' => ' wēn', + '豳' => ' bīn', + '豙' => ' yì', + '貀' => ' nà', + '貊' => ' mò', + '貉' => ' háo', + '貈' => ' hé', + '貇' => ' kūn', + '貆' => ' huán', + '貅' => ' xiū', + '貄' => ' sì', + '貃' => ' mò', + '貂' => ' diāo', + '貁' => ' yòu', + '豿' => ' gǒu', + '豴' => ' dí', + '豾' => ' pī', + '豽' => ' nà', + '豼' => ' pí', + '豻' => ' àn', + '豺' => ' chái', + '豹' => ' bào', + '豸' => ' zhì', + '豷' => ' yì', + '豶' => ' fén', + '豵' => ' zōng', + '豚' => ' tún', + '豘' => ' tún', + '貌' => ' mào', + '谲' => ' jué', + '谼' => ' hóng', + '谻' => ' jí', + '谺' => ' xiā', + '谹' => ' hóng', + '谸' => ' qiān', + '谷' => ' gǔ', + '谶' => ' chèn', + '谵' => ' zhān', + '谴' => ' qiǎn', + '谳' => ' yàn', + '谱' => ' pǔ', + '谾' => ' hōng', + '谰' => ' lán', + '谯' => ' qiáo', + '谮' => ' zèn', + '谭' => ' tán', + '谬' => ' miù', + '谫' => ' jiǎn', + '谪' => ' zhé', + '谩' => ' mán', + '谨' => ' jǐn', + '谧' => ' mì', + '谽' => ' hān', + '谿' => ' xī', + '豗' => ' huī', + '豌' => ' wān', + '豖' => ' chù', + '豕' => ' shǐ', + '豔' => ' yàn', + '豓' => ' yàn', + '豒' => ' zhì', + '豑' => ' zhì', + '豐' => ' fēng', + '豏' => ' xiàn', + '豎' => ' shù', + '豍' => ' bī', + '豋' => ' dēng', + '豀' => ' xī', + '豊' => ' lǐ', + '豉' => ' shì', + '豈' => ' qǐ', + '豇' => ' jiāng', + '豆' => ' dòu', + '豅' => ' lóng', + '豄' => ' dú', + '豃' => ' hǎn', + '豂' => ' liáo', + '豁' => ' huō', + '貋' => ' hàn', + '貍' => ' lí', + '賳' => ' zāi', + '賎' => ' jiàn', + '賘' => ' zāng', + '賗' => ' chuàn', + '賖' => ' shē', + '賕' => ' qiú', + '賔' => ' bīn', + '賓' => ' bīn', + '賒' => ' shē', + '賑' => ' zhèn', + '賐' => ' xùn', + '賏' => ' yīng', + '賍' => ' zāng', + '賚' => ' lài', + '賌' => ' gài', + '賋' => ' jiǎo', + '賊' => ' zéi', + '賉' => ' xù', + '賈' => ' jiǎ', + '資' => ' zī', + '賆' => ' pián', + '賅' => ' gāi', + '賄' => ' huì', + '賃' => ' lìn', + '賙' => ' zhōu', + '賛' => ' zàn', + '賁' => ' bì', + '賨' => ' cóng', + '賲' => ' bǎo', + '賱' => ' yǔn', + '賰' => ' chǔn', + '賯' => ' xiōng', + '賮' => ' jìn', + '賭' => ' dǔ', + '賬' => ' zhàng', + '賫' => ' jī', + '質' => ' zhì', + '賩' => ' cóng', + '賧' => ' tàn', + '賜' => ' cì', + '賦' => ' fù', + '賥' => ' suì', + '賤' => ' jiàn', + '賣' => ' mài', + '賢' => ' xián', + '賡' => ' gēng', + '賠' => ' péi', + '賟' => ' tiǎn', + '賞' => ' shǎng', + '賝' => ' chēn', + '賂' => ' lù', + '賀' => ' hè', + '貎' => ' ní', + '貚' => ' tán', + '貤' => ' yí', + '貣' => ' tè', + '貢' => ' gòng', + '財' => ' cái', + '負' => ' fù', + '貟' => ' yuán', + '貞' => ' zhēn', + '貝' => ' bèi', + '貜' => ' jué', + '貛' => ' huān', + '貙' => ' chū', + '貦' => ' wàn', + '貘' => ' mò', + '貗' => ' jù', + '貖' => ' è', + '貕' => ' xī', + '貔' => ' pí', + '貓' => ' māo', + '貒' => ' tuān', + '貑' => ' jiā', + '貐' => ' yǔ', + '貏' => ' bǐ', + '貥' => ' háng', + '貧' => ' pín', + '貿' => ' mào', + '貴' => ' guì', + '貾' => ' chí', + '貽' => ' yí', + '貼' => ' tiē', + '費' => ' fèi', + '貺' => ' kuàng', + '貹' => ' shèng', + '貸' => ' dài', + '買' => ' mǎi', + '貶' => ' biǎn', + '貵' => ' piǎn', + '貳' => ' èr', + '貨' => ' huò', + '貲' => ' zī', + '貱' => ' bì', + '貰' => ' shì', + '貯' => ' zhù', + '貮' => ' èr', + '貭' => ' zhí', + '責' => ' zé', + '貫' => ' guàn', + '貪' => ' tān', + '販' => ' fàn', + '跃' => ' yuè', + '跅' => ' tuò', + '轤' => ' lú', + '軗' => ' shū', + '軡' => ' qián', + '軠' => ' rèn', + '軟' => ' ruǎn', + '軞' => ' máo', + '軝' => ' qí', + '軜' => ' nà', + '軛' => ' è', + '軚' => ' dài', + '軙' => ' chén', + '軘' => ' tún', + '軖' => ' kuáng', + '軣' => ' hōng', + '軕' => ' shān', + '軔' => ' rèn', + '軓' => ' fàn', + '軒' => ' xuān', + '軑' => ' dài', + '軐' => ' xìn', + '軏' => ' yuè', + '軎' => ' wèi', + '軍' => ' jūn', + '軌' => ' guǐ', + '転' => ' zhuǎn', + '軤' => ' hū', + '車' => ' chē', + '軱' => ' gū', + '軻' => ' kē', + '軺' => ' yáo', + '軹' => ' zhǐ', + '軸' => ' zhóu', + '軷' => ' bá', + '軶' => ' è', + '軵' => ' rǒng', + '軴' => ' zhù', + '軳' => ' páo', + '軲' => ' gū', + '軰' => ' bèi', + '軥' => ' qú', + '軯' => ' pēng', + '軮' => ' yǎng', + '軭' => ' kuāng', + '軬' => ' fàn', + '軫' => ' zhěn', + '軪' => ' āo', + '軩' => ' dài', + '軨' => ' líng', + '軧' => ' dǐ', + '軦' => ' kuàng', + '軋' => ' yà', + '軉' => ' yù', + '軽' => ' zhì', + '躣' => ' qú', + '躭' => ' dān', + '躬' => ' gōng', + '身' => ' shēn', + '躪' => ' lìn', + '躩' => ' jué', + '躨' => ' kuí', + '躧' => ' xǐ', + '躦' => ' cuó', + '躥' => ' cuān', + '躤' => ' jiè', + '躢' => ' tà', + '躯' => ' qū', + '躡' => ' niè', + '躠' => ' sǎ', + '躟' => ' ráng', + '躞' => ' xiè', + '躝' => ' lán', + '躜' => ' zuān', + '躛' => ' wèi', + '躚' => ' xiān', + '躙' => ' lìn', + '躘' => ' lóng', + '躮' => ' fen', + '躰' => ' tǐ', + '軈' => ' ying', + '躽' => ' yǎn', + '軇' => ' dào', + '軆' => ' tǐ', + '軅' => ' yan', + '軄' => ' zhí', + '軃' => ' duǒ', + '軂' => ' lào', + '軁' => ' lóu', + '軀' => ' qū', + '躿' => ' kāng', + '躾' => ' mei', + '躼' => ' lào', + '躱' => ' duǒ', + '躻' => ' kong', + '躺' => ' tǎng', + '躹' => ' jú', + '躸' => ' jī', + '躷' => ' ǎi', + '躶' => ' luǒ', + '躵' => ' ren', + '躴' => ' láng', + '躳' => ' gōng', + '躲' => ' duǒ', + '軼' => ' yì', + '軾' => ' shì', + '躖' => ' duàn', + '輿' => ' yú', + '轉' => ' zhuǎn', + '轈' => ' cháo', + '轇' => ' jiāo', + '轆' => ' lù', + '轅' => ' yuán', + '轄' => ' xiá', + '轃' => ' zhēn', + '轂' => ' gǔ', + '轁' => ' tāo', + '轀' => ' wēn', + '輾' => ' zhǎn', + '轋' => ' hún', + '輽' => ' bèn', + '輼' => ' wēn', + '輻' => ' fú', + '輺' => ' zī', + '輹' => ' fù', + '輸' => ' shū', + '輷' => ' hōng', + '輶' => ' yóu', + '輵' => ' gé', + '輴' => ' chūn', + '轊' => ' wèi', + '轌' => ' xue', + '輲' => ' chuán', + '轙' => ' yǐ', + '轣' => ' lì', + '轢' => ' lì', + '轡' => ' pèi', + '轠' => ' léi', + '轟' => ' hōng', + '轞' => ' jiàn', + '轝' => ' yù', + '轜' => ' ér', + '轛' => ' zhuì', + '轚' => ' jí', + '轘' => ' huán', + '轍' => ' zhé', + '轗' => ' kǎn', + '轖' => ' sè', + '轕' => ' gé', + '轔' => ' lín', + '轓' => ' fān', + '轒' => ' fén', + '轑' => ' lǎo', + '轐' => ' bú', + '轏' => ' zhàn', + '轎' => ' jiào', + '輳' => ' còu', + '輱' => ' xián', + '軿' => ' píng', + '輋' => ' shē', + '輕' => ' qīng', + '輔' => ' fǔ', + '輓' => ' wǎn', + '輒' => ' zhé', + '輑' => ' yǐn', + '輐' => ' wàn', + '輏' => ' yóu', + '輎' => ' shāo', + '輍' => ' yù', + '輌' => ' liàng', + '輊' => ' zhì', + '輗' => ' ní', + '載' => ' zài', + '輈' => ' zhōu', + '輇' => ' quán', + '輆' => ' kǎi', + '輅' => ' hé', + '輄' => ' guāng', + '較' => ' jiào', + '輂' => ' jú', + '輁' => ' gǒng', + '輀' => ' ér', + '輖' => ' zhōu', + '輘' => ' léng', + '輰' => ' yáng', + '輥' => ' gǔn', + '輯' => ' jí', + '輮' => ' róu', + '輭' => ' ruǎn', + '輬' => ' liáng', + '輫' => ' pái', + '輪' => ' lún', + '輩' => ' bèi', + '輨' => ' guǎn', + '輧' => ' píng', + '輦' => ' niǎn', + '輤' => ' qiàn', + '輙' => ' zhé', + '輣' => ' péng', + '輢' => ' yǐ', + '輡' => ' kǎn', + '輠' => ' guǒ', + '輟' => ' chuò', + '輞' => ' wǎng', + '輝' => ' huī', + '輜' => ' zī', + '輛' => ' liàng', + '輚' => ' zhàn', + '躗' => ' wèi', + '躕' => ' chú', + '跆' => ' tái', + '踆' => ' cūn', + '踐' => ' jiàn', + '踏' => ' tà', + '踎' => ' móu', + '踍' => ' qiāo', + '踌' => ' chóu', + '踋' => ' jiǎo', + '踊' => ' yǒng', + '踉' => ' liáng', + '踈' => ' shū', + '踇' => ' mǔ', + '踅' => ' xué', + '踒' => ' wō', + '踄' => ' bù', + '踃' => ' xiāo', + '踂' => ' niè', + '踁' => ' jìng', + '踀' => ' chù', + '跿' => ' tú', + '跾' => ' shū', + '跽' => ' jì', + '跼' => ' jú', + '跻' => ' jī', + '踑' => ' qí', + '踓' => ' wěi', + '跹' => ' xiān', + '踠' => ' wǎn', + '踪' => ' zōng', + '踩' => ' cǎi', + '踨' => ' zōng', + '踧' => ' cù', + '踦' => ' yǐ', + '踥' => ' qiè', + '踤' => ' zú', + '踣' => ' bó', + '踢' => ' tī', + '踡' => ' quán', + '踟' => ' chí', + '踔' => ' chuō', + '踞' => ' jù', + '踝' => ' huái', + '踜' => ' lèng', + '踛' => ' lù', + '踚' => ' lún', + '踙' => ' jū', + '踘' => ' jū', + '踗' => ' niè', + '踖' => ' jí', + '踕' => ' jié', + '跺' => ' duò', + '跸' => ' bì', + '踬' => ' zhì', + '跒' => ' qiǎ', + '跜' => ' ní', + '跛' => ' bǒ', + '跚' => ' shān', + '跙' => ' jù', + '跘' => ' pán', + '跗' => ' fū', + '跖' => ' zhí', + '跕' => ' diǎn', + '跔' => ' jū', + '跓' => ' zhù', + '跑' => ' pǎo', + '跞' => ' lì', + '跐' => ' cī', + '跏' => ' jiā', + '跎' => ' tuó', + '跍' => ' kū', + '跌' => ' diē', + '跋' => ' bá', + '跊' => ' mèi', + '跉' => ' líng', + '跈' => ' niǎn', + '跇' => ' yì', + '距' => ' jù', + '跟' => ' gēn', + '跷' => ' qiāo', + '跬' => ' kuǐ', + '跶' => ' tà', + '践' => ' jiàn', + '跴' => ' cǎi', + '跳' => ' tiào', + '跲' => ' jiá', + '跱' => ' zhì', + '跰' => ' pián', + '路' => ' lù', + '跮' => ' chì', + '跭' => ' xiáng', + '跫' => ' qióng', + '跠' => ' yí', + '跪' => ' guì', + '跩' => ' zhuǎi', + '跨' => ' kuà', + '跧' => ' quán', + '跦' => ' zhū', + '跥' => ' duò', + '跤' => ' jiāo', + '跣' => ' xiǎn', + '跢' => ' duò', + '跡' => ' jī', + '踫' => ' pèng', + '踭' => ' zhēng', + '躔' => ' chán', + '蹯' => ' fán', + '蹹' => ' tá', + '蹸' => ' lìn', + '蹷' => ' jué', + '蹶' => ' jué', + '蹵' => ' cù', + '蹴' => ' cù', + '蹳' => ' bō', + '蹲' => ' dūn', + '蹱' => ' zhōng', + '蹰' => ' chú', + '蹮' => ' xiān', + '蹻' => ' juē', + '蹭' => ' cèng', + '蹬' => ' dēng', + '蹫' => ' jú', + '蹪' => ' tuí', + '蹩' => ' bié', + '蹨' => ' niǎn', + '蹧' => ' zāo', + '蹦' => ' bèng', + '蹥' => ' lián', + '蹤' => ' zōng', + '蹺' => ' qiāo', + '蹼' => ' pǔ', + '蹢' => ' dí', + '躉' => ' dǔn', + '躓' => ' zhì', + '躒' => ' lì', + '躑' => ' zhí', + '躐' => ' liè', + '躏' => ' lìn', + '躎' => ' niǎn', + '躍' => ' yuè', + '躌' => ' wǔ', + '躋' => ' jī', + '躊' => ' chóu', + '躈' => ' qiào', + '蹽' => ' liāo', + '躇' => ' chú', + '躆' => ' jù', + '躅' => ' zhú', + '躄' => ' bì', + '躃' => ' bì', + '躂' => ' dá', + '躁' => ' zào', + '躀' => ' kuàng', + '蹿' => ' cuān', + '蹾' => ' dūn', + '蹣' => ' pán', + '蹡' => ' qiāng', + '踮' => ' diǎn', + '踺' => ' jiàn', + '蹄' => ' tí', + '蹃' => ' nuò', + '蹂' => ' róu', + '蹁' => ' pián', + '蹀' => ' dié', + '踿' => ' zú', + '踾' => ' fú', + '踽' => ' jǔ', + '踼' => ' táng', + '踻' => ' guā', + '踹' => ' chuài', + '蹆' => ' tuǐ', + '踸' => ' chěn', + '踷' => ' zhǎ', + '踶' => ' dì', + '踵' => ' zhǒng', + '踴' => ' yǒng', + '踳' => ' chuǎn', + '踲' => ' dùn', + '踱' => ' duó', + '踰' => ' yú', + '踯' => ' zhí', + '蹅' => ' chǎ', + '蹇' => ' jiǎn', + '蹠' => ' zhí', + '蹕' => ' bì', + '蹟' => ' jī', + '蹞' => ' kuǐ', + '蹝' => ' xǐ', + '蹜' => ' sù', + '蹛' => ' dài', + '蹚' => ' tāng', + '蹙' => ' cù', + '蹘' => ' liáo', + '蹗' => ' lù', + '蹖' => ' chōng', + '蹔' => ' zàn', + '蹈' => ' dǎo', + '蹓' => ' liū', + '蹒' => ' pán', + '蹑' => ' niè', + '蹐' => ' jí', + '蹏' => ' tí', + '蹎' => ' diān', + '蹍' => ' niǎn', + '蹌' => ' qiāng', + '蹋' => ' tà', + '蹊' => ' qī', + '蹉' => ' cuō', + '殛' => ' jí', + '敢' => ' gǎn', + '殙' => ' hūn', + '䠓' => ' qiū', + '䠞' => ' cù', + '䠝' => ' xūn', + '䠜' => ' róng', + '䠛' => ' yáo', + '䠚' => ' wà', + '䠙' => ' páng', + '䠘' => ' pì', + '䠗' => ' qiù', + '䠕' => ' cāi', + '䠔' => ' suì', + '䠒' => ' hú', + '䠠' => ' chì', + '䠑' => ' kuǐ', + '䠐' => ' qù', + '䠏' => ' jì', + '䠎' => ' wò', + '䠍' => ' xiā', + '䠋' => ' bì', + '䠊' => ' fèi', + '䠉' => ' huàn', + '䠈' => ' tú', + '䠇' => ' jué', + '䠟' => ' dié', + '䠡' => ' cuó', + '䠅' => ' kǔn', + '䠮' => ' téng', + '䠸' => ' kuā', + '䠷' => ' tiǎo', + '䠶' => ' shè', + '䠵' => ' fù', + '䠴' => ' zhěn', + '䠳' => ' chēn', + '䠲' => ' líng', + '䠱' => ' zhú', + '䠰' => ' quán', + '䠯' => ' yuè', + '䠭' => ' lái', + '䠢' => ' mèng', + '䠬' => ' dèng', + '䠫' => ' zòu', + '䠪' => ' duàn', + '䠩' => ' guì', + '䠨' => ' chàn', + '䠧' => ' chú', + '䠦' => ' zhè', + '䠥' => ' bié', + '䠤' => ' duǒ', + '䠣' => ' xuǎn', + '䠆' => ' cháng', + '䠄' => ' tiǎn', + '䠻' => ' qióng', + '䟙' => ' qiè', + '䟣' => ' chù', + '䟢' => ' chén', + '䟡' => ' zhī', + '䟠' => ' yuè', + '䟟' => ' cù', + '䟞' => ' chú', + '䟝' => ' tòu', + '䟜' => ' nà', + '䟛' => ' bó', + '䟚' => ' qí', + '䟘' => ' hàng', + '䟥' => ' méng', + '䟗' => ' shì', + '䟖' => ' tàng', + '䟕' => ' chà', + '䟔' => ' fù', + '䟓' => ' chēng', + '䟒' => ' quán', + '䟑' => ' yuè', + '䟐' => ' lì', + '䟏' => ' lì', + '䟍' => ' biān', + '䟤' => ' bì', + '䟦' => ' bá', + '䠃' => ' liǎng', + '䟶' => ' zuò', + '䠂' => ' chú', + '䠀' => ' tāng', + '䟿' => ' lù', + '䟾' => ' zhuó', + '䟼' => ' wǔ', + '䟻' => ' dù', + '䟺' => ' bèi', + '䟹' => ' liè', + '䟸' => ' kuí', + '䟷' => ' chì', + '䟵' => ' qiú', + '䟧' => ' tián', + '䟴' => ' zhèn', + '䟰' => ' jiǎn', + '䟯' => ' kuò', + '䟮' => ' fú', + '䟭' => ' tiáo', + '䟬' => ' qiù', + '䟫' => ' chēng', + '䟪' => ' fěng', + '䟩' => ' liě', + '䟨' => ' mín', + '䠹' => ' ái', + '䠼' => ' shù', + '䟋' => ' zhǎn', + '䢁' => ' yuè', + '䢍' => ' fǎng', + '䢌' => ' bó', + '䢋' => ' jì', + '䢊' => ' yóu', + '䢉' => ' nóng', + '䢈' => ' chén', + '䢇' => ' rǒng', + '䢅' => ' chén', + '䢄' => ' xǐ', + '䢃' => ' yì', + '䢀' => ' qì', + '䢑' => ' dǐ', + '䡿' => ' líng', + '䡾' => ' niè', + '䡽' => ' zuān', + '䡼' => ' líng', + '䡻' => ' mín', + '䡺' => ' wèi', + '䡹' => ' zhì', + '䡷' => ' kài', + '䡶' => ' bèi', + '䡵' => ' suì', + '䢐' => ' cú', + '䢒' => ' jiāo', + '䡳' => ' sī', + '䢡' => ' yè', + '䢫' => ' suí', + '䢪' => ' bó', + '䢩' => ' yù', + '䢨' => ' cōng', + '䢧' => ' liào', + '䢦' => ' shuài', + '䢥' => ' yán', + '䢤' => ' shù', + '䢣' => ' yáo', + '䢢' => ' càng', + '䢠' => ' sòng', + '䢓' => ' yú', + '䢟' => ' yóu', + '䢞' => ' shù', + '䢝' => ' yà', + '䢛' => ' jiǒng', + '䢚' => ' gēng', + '䢙' => ' bài', + '䢗' => ' qū', + '䢖' => ' yù', + '䢕' => ' xù', + '䢔' => ' hé', + '䡴' => ' chōng', + '䡲' => ' chán', + '䠽' => ' hái', + '䡊' => ' fǎn', + '䡔' => ' qǐ', + '䡓' => ' juàn', + '䡒' => ' tián', + '䡑' => ' mín', + '䡐' => ' tuó', + '䡏' => ' hóng', + '䡎' => ' lú', + '䡍' => ' fú', + '䡌' => ' hóng', + '䡋' => ' qí', + '䡉' => ' kǎng', + '䡖' => ' qìng', + '䡈' => ' jué', + '䡇' => ' yuè', + '䡆' => ' róng', + '䡅' => ' chūn', + '䡃' => ' lì', + '䡂' => ' jiū', + '䡁' => ' lǒng', + '䡀' => ' zhǎn', + '䠿' => ' wài', + '䠾' => ' shǎn', + '䡕' => ' zhěng', + '䡗' => ' gǒng', + '䡱' => ' zhuǎn', + '䡥' => ' róng', + '䡰' => ' kēng', + '䡯' => ' cōng', + '䡭' => ' xiū', + '䡬' => ' màn', + '䡫' => ' péng', + '䡪' => ' shàn', + '䡩' => ' kēng', + '䡨' => ' chà', + '䡧' => ' wū', + '䡦' => ' sǎng', + '䡤' => ' zhū', + '䡘' => ' tián', + '䡣' => ' hūn', + '䡢' => ' biàn', + '䡡' => ' xié', + '䡟' => ' pì', + '䡞' => ' jú', + '䡝' => ' yuān', + '䡜' => ' lù', + '䡛' => ' yìn', + '䡚' => ' mào', + '䡙' => ' láng', + '䟌' => ' jí', + '䟊' => ' qú', + '䢮' => ' lèi', + '䜱' => ' mǎn', + '䜼' => ' gú', + '䜻' => ' chǐ', + '䜺' => ' chǎi', + '䜹' => ' shù', + '䜸' => ' měi', + '䜷' => ' qīn', + '䜶' => ' xiáng', + '䜵' => ' chǐ', + '䜴' => ' chù', + '䜲' => ' liè', + '䜯' => ' jú', + '䜾' => ' yīn', + '䜮' => ' liáo', + '䜭' => ' jùn', + '䜬' => ' sǒng', + '䜫' => ' jiāng', + '䜪' => ' qiú', + '䜩' => ' yàn', + '䜧' => ' nǎo', + '䜣' => ' xīn', + '䜢' => ' xiǎn', + '䜡' => ' yù', + '䜽' => ' yú', + '䝀' => ' liú', + '䜟' => ' chén', + '䝐' => ' wéi', + '䝜' => ' suān', + '䝛' => ' bō', + '䝚' => ' ní', + '䝙' => ' chū', + '䝘' => ' yì', + '䝖' => ' zhǎo', + '䝕' => ' zhé', + '䝓' => ' liè', + '䝒' => ' zhù', + '䝑' => ' chōng', + '䝏' => ' lóu', + '䝁' => ' láo', + '䝎' => ' tuān', + '䝍' => ' jùn', + '䝌' => ' jué', + '䝋' => ' zòng', + '䝊' => ' shà', + '䝈' => ' è', + '䝅' => ' huī', + '䝄' => ' shuāng', + '䝃' => ' zhé', + '䝂' => ' shù', + '䜠' => ' chè', + '䜞' => ' jì', + '䝞' => ' hào', + '䛷' => ' wǎn', + '䜁' => ' xì', + '䜀' => ' nǎo', + '䛿' => ' gé', + '䛾' => ' sù', + '䛽' => ' zhǎ', + '䛼' => ' huǐ', + '䛻' => ' yòu', + '䛺' => ' jiè', + '䛹' => ' càn', + '䛸' => ' chè', + '䛶' => ' lěi', + '䜄' => ' chí', + '䛵' => ' shòu', + '䛴' => ' jī', + '䛳' => ' yàn', + '䛲' => ' mán', + '䛱' => ' tí', + '䛰' => ' hùn', + '䛯' => ' jù', + '䛮' => ' jiù', + '䛭' => ' xìng', + '䛬' => ' táo', + '䜃' => ' duī', + '䜅' => ' wéi', + '䜝' => ' tuǎn', + '䜒' => ' ào', + '䜜' => ' wèi', + '䜛' => ' chán', + '䜚' => ' tà', + '䜙' => ' án', + '䜘' => ' jǐng', + '䜗' => ' xìn', + '䜖' => ' tàn', + '䜕' => ' mài', + '䜔' => ' suí', + '䜓' => ' shè', + '䜑' => ' wù', + '䜆' => ' zhé', + '䜐' => ' huī', + '䜏' => ' tuō', + '䜎' => ' láo', + '䜍' => ' liáo', + '䜌' => ' luán', + '䜋' => ' huì', + '䜊' => ' zāo', + '䜉' => ' chī', + '䜈' => ' chāo', + '䜇' => ' gǔn', + '䝝' => ' yǐ', + '䝟' => ' yà', + '䟉' => ' zhú', + '䞣' => ' chě', + '䞭' => ' cūn', + '䞬' => ' tòu', + '䞫' => ' yǔn', + '䞪' => ' jiàng', + '䞩' => ' è', + '䞨' => ' guǐ', + '䞧' => ' hòu', + '䞦' => ' hé', + '䞥' => ' yòu', + '䞤' => ' qú', + '䞢' => ' zuó', + '䞯' => ' fù', + '䞡' => ' tǎn', + '䞠' => ' zhī', + '䞟' => ' pò', + '䞞' => ' fú', + '䞝' => ' yù', + '䞜' => ' fù', + '䞛' => ' yān', + '䞚' => ' qí', + '䞙' => ' zá', + '䞘' => ' jí', + '䞮' => ' tū', + '䞰' => ' zuó', + '䞖' => ' shǔ', + '䞾' => ' chí', + '䟈' => ' zhí', + '䟇' => ' jī', + '䟆' => ' bì', + '䟅' => ' jiàn', + '䟄' => ' qì', + '䟃' => ' cān', + '䟂' => ' mán', + '䟁' => ' xiáo', + '䟀' => ' cāi', + '䞿' => ' qiān', + '䞽' => ' suǒ', + '䞱' => ' hú', + '䞼' => ' chuǐ', + '䞻' => ' yǒng', + '䞺' => ' chūn', + '䞹' => ' huáng', + '䞸' => ' fù', + '䞷' => ' jué', + '䞶' => ' tāng', + '䞵' => ' juě', + '䞴' => ' zhāo', + '䞳' => ' bó', + '䞗' => ' cāi', + '䞕' => ' rú', + '䝠' => ' huán', + '䝬' => ' zhù', + '䝷' => ' zhī', + '䝶' => ' liáng', + '䝵' => ' bù', + '䝳' => ' cán', + '䝲' => ' jìn', + '䝱' => ' xié', + '䝰' => ' zhì', + '䝯' => ' yì', + '䝮' => ' xuàn', + '䝭' => ' gòu', + '䝫' => ' zuó', + '䝹' => ' wǎn', + '䝪' => ' shǔ', + '䝩' => ' zhèn', + '䝨' => ' xián', + '䝧' => ' mín', + '䝦' => ' zhōng', + '䝥' => ' háo', + '䝤' => ' lǎo', + '䝣' => ' qú', + '䝢' => ' màn', + '䝡' => ' màn', + '䝸' => ' jì', + '䝺' => ' guàn', + '䞔' => ' wěi', + '䞇' => ' dié', + '䞓' => ' chēng', + '䞒' => ' dòng', + '䞑' => ' hóng', + '䞐' => ' chǔn', + '䞍' => ' qíng', + '䞌' => ' shé', + '䞋' => ' chèn', + '䞊' => ' xùn', + '䞉' => ' shèng', + '䞈' => ' guì', + '䞆' => ' suǒ', + '䝻' => ' jū', + '䞅' => ' yí', + '䞄' => ' biào', + '䞃' => ' zhì', + '䞂' => ' ruǎn', + '䞁' => ' yàn', + '䞀' => ' hòu', + '䝿' => ' guì', + '䝾' => ' fù', + '䝽' => ' ài', + '䝼' => ' jìng', + '䢭' => ' yàn', + '䢯' => ' lín', + '䛪' => ' qióng', + '䧤' => ' pú', + '䧰' => ' hùn', + '䧯' => ' chán', + '䧮' => ' xiàn', + '䧬' => ' bīn', + '䧫' => ' háo', + '䧪' => ' chè', + '䧨' => ' yè', + '䧧' => ' yǐ', + '䧦' => ' wéi', + '䧥' => ' huì', + '䧢' => ' qū', + '䧳' => ' cí', + '䧡' => ' yōng', + '䧠' => ' shuàn', + '䧟' => ' xiàn', + '䧞' => ' mà', + '䧝' => ' chī', + '䧜' => ' táng', + '䧛' => ' bàng', + '䧚' => ' hào', + '䧙' => ' líng', + '䧘' => ' zhuàn', + '䧲' => ' hàn', + '䧴' => ' zhī', + '䧖' => ' jiàn', + '䨅' => ' liáo', + '䨑' => ' tí', + '䨐' => ' qià', + '䨏' => ' cí', + '䨎' => ' hóng', + '䨍' => ' yǐng', + '䨌' => ' báo', + '䨋' => ' nüè', + '䨊' => ' yuān', + '䨈' => ' bīn', + '䨆' => ' bí', + '䨄' => ' yàn', + '䧵' => ' qí', + '䨂' => ' qiū', + '䨁' => ' wù', + '䨀' => ' dí', + '䧿' => ' què', + '䧽' => ' cuǐ', + '䧼' => ' hú', + '䧺' => ' xióng', + '䧹' => ' yīng', + '䧷' => ' róu', + '䧶' => ' kuí', + '䧗' => ' bì', + '䧕' => ' chéng', + '䨓' => ' léi', + '䦧' => ' qié', + '䦳' => ' xiàng', + '䦲' => ' yán', + '䦱' => ' wěi', + '䦯' => ' zhì', + '䦮' => ' chǔn', + '䦭' => ' hāng', + '䦬' => ' què', + '䦫' => ' yīng', + '䦪' => ' yà', + '䦨' => ' lán', + '䦦' => ' qín', + '䦵' => ' nǐ', + '䦥' => ' xián', + '䦤' => ' chuài', + '䦣' => ' fù', + '䦢' => ' kuò', + '䦡' => ' huán', + '䦠' => ' dū', + '䦟' => ' wěn', + '䦞' => ' rùn', + '䦝' => ' huō', + '䦜' => ' wú', + '䦴' => ' yì', + '䦶' => ' zhèng', + '䧔' => ' niàn', + '䧆' => ' hóng', + '䧓' => ' zhōu', + '䧒' => ' lái', + '䧑' => ' dī', + '䧎' => ' xuàn', + '䧍' => ' xì', + '䧌' => ' suī', + '䧋' => ' xiǎn', + '䧊' => ' kū', + '䧉' => ' lǐ', + '䧇' => ' yī', + '䧅' => ' yí', + '䦷' => ' chuài', + '䧄' => ' gè', + '䧃' => ' tián', + '䧂' => ' dào', + '䧁' => ' xǔ', + '䦾' => ' yuán', + '䦽' => ' xù', + '䦼' => ' jué', + '䦻' => ' zǐ', + '䦺' => ' dīng', + '䦹' => ' shí', + '䨒' => ' yù', + '䨔' => ' báo', + '䦚' => ' kuà', + '䩙' => ' xuàn', + '䩤' => ' xié', + '䩣' => ' tú', + '䩢' => ' zhì', + '䩡' => ' jiá', + '䩟' => ' yí', + '䩞' => ' tié', + '䩝' => ' páo', + '䩜' => ' zhòu', + '䩛' => ' bì', + '䩚' => ' dì', + '䩘' => ' dì', + '䩦' => ' tiáo', + '䩗' => ' bà', + '䩕' => ' áng', + '䩔' => ' duò', + '䩓' => ' qí', + '䩒' => ' yú', + '䩑' => ' hóng', + '䩐' => ' hū', + '䩏' => ' miè', + '䩍' => ' liǎo', + '䩌' => ' qiáo', + '䩥' => ' dàn', + '䩧' => ' xiè', + '䩊' => ' wǎn', + '䩵' => ' yùn', + '䩿' => ' fén', + '䩾' => ' zhè', + '䩽' => ' yū', + '䩼' => ' féng', + '䩻' => ' bà', + '䩺' => ' wēng', + '䩹' => ' é', + '䩸' => ' róng', + '䩷' => ' bāng', + '䩶' => ' chǎn', + '䩴' => ' hú', + '䩨' => ' chàng', + '䩳' => ' sōu', + '䩲' => ' dū', + '䩱' => ' shù', + '䩰' => ' xuàn', + '䩯' => ' jí', + '䩮' => ' lù', + '䩬' => ' běng', + '䩫' => ' liǎng', + '䩪' => ' guǎn', + '䩩' => ' yuǎn', + '䩋' => ' mǒ', + '䩉' => ' fǔ', + '䨖' => ' jì', + '䨢' => ' dàn', + '䨭' => ' xiāo', + '䨬' => ' lián', + '䨫' => ' mài', + '䨪' => ' mái', + '䨩' => ' líng', + '䨨' => ' zhuī', + '䨦' => ' pāng', + '䨥' => ' huò', + '䨤' => ' dí', + '䨣' => ' gé', + '䨡' => ' hán', + '䨯' => ' zhèn', + '䨠' => ' ǎi', + '䨟' => ' wā', + '䨞' => ' yǔ', + '䨝' => ' qīng', + '䨜' => ' bēng', + '䨛' => ' sè', + '䨚' => ' hū', + '䨙' => ' cén', + '䨘' => ' xiàn', + '䨗' => ' fú', + '䨮' => ' xuě', + '䨰' => ' pò', + '䩈' => ' huì', + '䨽' => ' fěi', + '䩇' => ' zhān', + '䩆' => ' zhǎn', + '䩅' => ' zhǎn', + '䩄' => ' miǎn', + '䩃' => ' shì', + '䩂' => ' xiān', + '䩁' => ' fēi', + '䩀' => ' bèi', + '䨿' => ' zá', + '䨾' => ' fèi', + '䨼' => ' hù', + '䨱' => ' fù', + '䨻' => ' bèng', + '䨺' => ' duì', + '䨹' => ' shū', + '䨸' => ' yǐn', + '䨷' => ' xiàn', + '䨶' => ' yǔn', + '䨵' => ' dàn', + '䨴' => ' duì', + '䨳' => ' xì', + '䨲' => ' nóu', + '䦛' => ' zhèng', + '䦙' => ' sì', + '䢰' => ' tī', + '䣹' => ' fá', + '䤄' => ' miǎn', + '䤃' => ' yīn', + '䤂' => ' méi', + '䤁' => ' cén', + '䣿' => ' yū', + '䣾' => ' mì', + '䣽' => ' zhī', + '䣼' => ' liáng', + '䣻' => ' hān', + '䣺' => ' juān', + '䣸' => ' rǎn', + '䤆' => ' kuí', + '䣷' => ' zhū', + '䣶' => ' huó', + '䣵' => ' èr', + '䣴' => ' xù', + '䣲' => ' fàn', + '䣱' => ' xù', + '䣰' => ' jù', + '䣯' => ' cú', + '䣮' => ' pò', + '䣭' => ' tài', + '䤅' => ' tú', + '䤉' => ' mì', + '䣫' => ' lí', + '䤖' => ' bào', + '䤠' => ' zhǐ', + '䤟' => ' chén', + '䤞' => ' yǔn', + '䤝' => ' yìng', + '䤜' => ' dùn', + '䤛' => ' qiú', + '䤚' => ' lǐ', + '䤙' => ' lì', + '䤘' => ' chǎn', + '䤗' => ' gǎn', + '䤕' => ' xuè', + '䤊' => ' róng', + '䤔' => ' jiàn', + '䤓' => ' méng', + '䤒' => ' jì', + '䤑' => ' wàng', + '䤐' => ' jǐn', + '䤏' => ' pǐ', + '䤎' => ' jú', + '䤍' => ' mí', + '䤌' => ' qiāng', + '䤋' => ' yù', + '䣬' => ' zǎi', + '䣪' => ' pò', + '䤣' => ' lüè', + '䢿' => ' ān', + '䣋' => ' cǎi', + '䣊' => ' dǎng', + '䣈' => ' hàng', + '䣇' => ' qiú', + '䣆' => ' xíng', + '䣅' => ' chén', + '䣄' => ' tú', + '䣂' => ' lěi', + '䣁' => ' yǔ', + '䣀' => ' guǐ', + '䢾' => ' xiǎn', + '䣍' => ' yǎn', + '䢽' => ' xiàng', + '䢼' => ' gōng', + '䢻' => ' chén', + '䢺' => ' chū', + '䢹' => ' jǔ', + '䢸' => ' jū', + '䢵' => ' yún', + '䢳' => ' jǐ', + '䢲' => ' yuè', + '䢱' => ' dú', + '䣌' => ' dǐ', + '䣎' => ' zī', + '䣩' => ' chún', + '䣞' => ' è', + '䣨' => ' chún', + '䣧' => ' yì', + '䣦' => ' lèi', + '䣥' => ' bǐ', + '䣤' => ' jué', + '䣣' => ' dǎng', + '䣢' => ' jí', + '䣡' => ' yí', + '䣠' => ' jié', + '䣟' => ' cán', + '䣝' => ' tú', + '䣐' => ' yīng', + '䣜' => ' cuó', + '䣛' => ' qī', + '䣚' => ' lóu', + '䣙' => ' péi', + '䣘' => ' táng', + '䣖' => ' mǎ', + '䣕' => ' mǎ', + '䣔' => ' suǒ', + '䣓' => ' lí', + '䣑' => ' chán', + '䤡' => ' rǎn', + '䤤' => ' kāi', + '䦘' => ' xiàn', + '䥪' => ' xiǎn', + '䥵' => ' xiǎo', + '䥳' => ' yōu', + '䥲' => ' ōu', + '䥱' => ' xiě', + '䥰' => ' méng', + '䥯' => ' bēi', + '䥮' => ' zhú', + '䥭' => ' zhèng', + '䥬' => ' bó', + '䥫' => ' tiě', + '䥩' => ' wéi', + '䥷' => ' zhá', + '䥨' => ' lǜ', + '䥧' => ' huán', + '䥥' => ' lián', + '䥤' => ' báo', + '䥣' => ' záo', + '䥢' => ' lóng', + '䥡' => ' yè', + '䥟' => ' yè', + '䥞' => ' jiǎo', + '䥝' => ' áo', + '䥶' => ' lì', + '䥸' => ' mí', + '䥛' => ' jiē', + '䦍' => ' wù', + '䦗' => ' xù', + '䦖' => ' xié', + '䦕' => ' pēng', + '䦔' => ' tǎn', + '䦓' => ' zhān', + '䦒' => ' dàng', + '䦑' => ' xuè', + '䦐' => ' tǐng', + '䦏' => ' xiè', + '䦎' => ' guǎn', + '䦌' => ' chù', + '䥺' => ' yé', + '䦋' => ' áo', + '䦊' => ' niǎo', + '䦈' => ' jiē', + '䦇' => ' jì', + '䦆' => ' jué', + '䦅' => ' shàn', + '䦃' => ' zhuō', + '䦂' => ' shàn', + '䥾' => ' xiě', + '䥽' => ' pō', + '䥜' => ' jiàn', + '䥙' => ' suì', + '䤥' => ' guǐ', + '䤱' => ' shì', + '䤻' => ' duò', + '䤺' => ' jīn', + '䤹' => ' sōu', + '䤸' => ' zuàn', + '䤷' => ' yǎn', + '䤶' => ' yè', + '䤵' => ' fèi', + '䤴' => ' hán', + '䤳' => ' yè', + '䤲' => ' chì', + '䤰' => ' yíng', + '䤽' => ' guān', + '䤯' => ' xíng', + '䤮' => ' shè', + '䤭' => ' shì', + '䤬' => ' shā', + '䤫' => ' chán', + '䤪' => ' duǒ', + '䤩' => ' chá', + '䤨' => ' pì', + '䤧' => ' huì', + '䤦' => ' yuè', + '䤼' => ' xiàn', + '䤾' => ' tāo', + '䥘' => ' cù', + '䥍' => ' zhì', + '䥗' => ' kuǎn', + '䥖' => ' tián', + '䥕' => ' piě', + '䥔' => ' sù', + '䥓' => ' qī', + '䥒' => ' jiàng', + '䥑' => ' wàn', + '䥐' => ' móu', + '䥏' => ' yǔ', + '䥎' => ' chún', + '䥌' => ' zhèng', + '䤿' => ' qiè', + '䥋' => ' pēng', + '䥉' => ' yuān', + '䥈' => ' mǔ', + '䥇' => ' shàn', + '䥆' => ' jǐn', + '䥅' => ' qiàn', + '䥄' => ' cù', + '䥃' => ' yuè', + '䥂' => ' mèng', + '䥁' => ' hán', + '䥀' => ' chǎn', + '䛫' => ' zhāng', + '䛩' => ' wù', + '䪁' => ' bǔ', + '䑹' => ' sōu', + '䒅' => ' téng', + '䒄' => ' fù', + '䒃' => ' cào', + '䒂' => ' jiǎng', + '䒁' => ' xí', + '䒀' => ' bù', + '䑿' => ' sù', + '䑽' => ' tà', + '䑼' => ' zhōu', + '䑻' => ' yóu', + '䑸' => ' zōng', + '䒇' => ' fù', + '䑶' => ' qiàn', + '䑵' => ' mù', + '䑴' => ' qí', + '䑳' => ' lún', + '䑲' => ' zhào', + '䑱' => ' wǎn', + '䑰' => ' bù', + '䑯' => ' dì', + '䑭' => ' dì', + '䑬' => ' tāo', + '䒆' => ' chè', + '䒈' => ' fèi', + '䑪' => ' è', + '䒕' => ' xiǎo', + '䒡' => ' yǐn', + '䒠' => ' fēng', + '䒟' => ' dān', + '䒞' => ' chén', + '䒝' => ' xiáo', + '䒜' => ' niú', + '䒛' => ' huàn', + '䒚' => ' shǎo', + '䒗' => ' qì', + '䒖' => ' xìn', + '䒔' => ' bài', + '䒉' => ' wǔ', + '䒓' => ' kǎi', + '䒒' => ' tiáo', + '䒑' => ' cǎo', + '䒐' => ' méng', + '䒏' => ' sēng', + '䒎' => ' mǎng', + '䒍' => ' pǎng', + '䒌' => ' mìng', + '䒋' => ' yǎng', + '䒊' => ' xī', + '䑫' => ' bēng', + '䑨' => ' duò', + '䒣' => ' rǎn', + '䐾' => ' duó', + '䑈' => ' bó', + '䑇' => ' zhì', + '䑆' => ' yǎng', + '䑅' => ' méng', + '䑄' => ' pì', + '䑃' => ' méng', + '䑂' => ' ǎi', + '䑁' => ' wù', + '䑀' => ' pì', + '䐿' => ' ào', + '䐽' => ' mán', + '䑊' => ' wéi', + '䐼' => ' xì', + '䐻' => ' gū', + '䐺' => ' tàn', + '䐹' => ' sōu', + '䐸' => ' huò', + '䐷' => ' dān', + '䐶' => ' zān', + '䐵' => ' gōng', + '䐴' => ' guì', + '䐳' => ' yú', + '䑉' => ' yíng', + '䑋' => ' rǎng', + '䑧' => ' fú', + '䑚' => ' tián', + '䑦' => ' gōu', + '䑥' => ' è', + '䑤' => ' jìn', + '䑣' => ' chēn', + '䑠' => ' liǎo', + '䑟' => ' huáng', + '䑞' => ' shùn', + '䑝' => ' jiǎ', + '䑜' => ' tà', + '䑛' => ' chǐ', + '䑙' => ' tān', + '䑌' => ' lán', + '䑘' => ' cuó', + '䑗' => ' dàng', + '䑕' => ' shǔ', + '䑔' => ' fèi', + '䑓' => ' tái', + '䑑' => ' pú', + '䑐' => ' zhěn', + '䑏' => ' quán', + '䑎' => ' chǎn', + '䑍' => ' yān', + '䒢' => ' áng', + '䒤' => ' rì', + '䐱' => ' zhài', + '䓯' => ' dú', + '䓹' => ' yì', + '䓸' => ' jiān', + '䓷' => ' xìng', + '䓶' => ' lài', + '䓵' => ' fū', + '䓴' => ' ruǎn', + '䓳' => ' hěn', + '䓲' => ' ruì', + '䓱' => ' chái', + '䓰' => ' yīn', + '䓮' => ' mào', + '䓼' => ' máng', + '䓭' => ' chà', + '䓫' => ' qí', + '䓨' => ' yīng', + '䓧' => ' cì', + '䓦' => ' diǎn', + '䓥' => ' là', + '䓤' => ' hū', + '䓣' => ' liǎng', + '䓢' => ' gù', + '䓡' => ' zhī', + '䓺' => ' měi', + '䓽' => ' jì', + '䓟' => ' zhōu', + '䔋' => ' suō', + '䔗' => ' xiáng', + '䔖' => ' líng', + '䔕' => ' pú', + '䔔' => ' jìng', + '䔓' => ' xǔ', + '䔒' => ' bèi', + '䔑' => ' xié', + '䔐' => ' jiān', + '䔏' => ' chòu', + '䔎' => ' sù', + '䔊' => ' bīng', + '䓾' => ' suō', + '䔉' => ' lì', + '䔈' => ' gòng', + '䔇' => ' qǐ', + '䔆' => ' lí', + '䔅' => ' gē', + '䔄' => ' yáo', + '䔃' => ' zǔ', + '䔂' => ' zǐ', + '䔁' => ' lì', + '䓿' => ' hàn', + '䓠' => ' tà', + '䓞' => ' lì', + '䒥' => ' mán', + '䒴' => ' yǒu', + '䒿' => ' liáo', + '䒾' => ' yī', + '䒽' => ' wǎng', + '䒼' => ' qū', + '䒻' => ' qǐ', + '䒺' => ' jǐn', + '䒹' => ' lèi', + '䒸' => ' xuè', + '䒷' => ' guā', + '䒵' => ' hào', + '䒳' => ' duǒ', + '䓃' => ' yì', + '䒲' => ' chà', + '䒰' => ' kuāng', + '䒭' => ' děng', + '䒬' => ' mò', + '䒫' => ' dài', + '䒪' => ' biàn', + '䒩' => ' hé', + '䒨' => ' shǐ', + '䒧' => ' qū', + '䒦' => ' fàn', + '䓂' => ' yán', + '䓄' => ' yín', + '䓝' => ' mèng', + '䓑' => ' píng', + '䓜' => ' zhī', + '䓛' => ' qū', + '䓚' => ' qū', + '䓙' => ' kuā', + '䓘' => ' gāo', + '䓗' => ' cōng', + '䓖' => ' qióng', + '䓕' => ' tuǒ', + '䓓' => ' chóu', + '䓒' => ' kuǎi', + '䓐' => ' chún', + '䓅' => ' qí', + '䓏' => ' fū', + '䓎' => ' chuò', + '䓍' => ' hǎn', + '䓌' => ' zhì', + '䓋' => ' zhī', + '䓊' => ' wú', + '䓉' => ' yé', + '䓈' => ' yì', + '䓇' => ' xì', + '䓆' => ' zhé', + '䐲' => ' zhé', + '䐰' => ' xiū', + '䔙' => ' diào', + '䎝' => ' chú', + '䎩' => ' zī', + '䎨' => ' yè', + '䎧' => ' bàng', + '䎦' => ' yǎn', + '䎤' => ' jú', + '䎣' => ' sì', + '䎢' => ' qǐ', + '䎡' => ' ruǎn', + '䎠' => ' ér', + '䎟' => ' ér', + '䎜' => ' hūn', + '䎫' => ' chuàng', + '䎚' => ' guàn', + '䎙' => ' pīn', + '䎘' => ' sù', + '䎗' => ' qiáo', + '䎖' => ' zēng', + '䎕' => ' hōng', + '䎔' => ' fū', + '䎓' => ' tà', + '䎒' => ' zhǎn', + '䎑' => ' lù', + '䎪' => ' nè', + '䎬' => ' bà', + '䎏' => ' hán', + '䎹' => ' wén', + '䏃' => ' mián', + '䏂' => ' sǒu', + '䏁' => ' zǎi', + '䏀' => ' là', + '䎿' => ' qiú', + '䎾' => ' gǔn', + '䎽' => ' wén', + '䎼' => ' lù', + '䎻' => ' zhòu', + '䎺' => ' zhì', + '䎸' => ' wù', + '䎭' => ' cāo', + '䎷' => ' zhù', + '䎶' => ' èr', + '䎵' => ' bì', + '䎴' => ' gēng', + '䎳' => ' wà', + '䎲' => ' zhé', + '䎱' => ' bà', + '䎰' => ' zuó', + '䎯' => ' hàn', + '䎮' => ' tì', + '䎐' => ' chǎo', + '䎎' => ' nà', + '䏅' => ' qì', + '䍣' => ' léi', + '䍯' => ' guǐ', + '䍮' => ' zhào', + '䍬' => ' pēng', + '䍫' => ' tuó', + '䍪' => ' wà', + '䍩' => ' yǎng', + '䍨' => ' pō', + '䍦' => ' lí', + '䍥' => ' lì', + '䍤' => ' jǐ', + '䍢' => ' wú', + '䍲' => ' nái', + '䍡' => ' lù', + '䍠' => ' lí', + '䍟' => ' zòng', + '䍞' => ' yù', + '䍝' => ' tà', + '䍜' => ' zhào', + '䍛' => ' gù', + '䍚' => ' làng', + '䍙' => ' méi', + '䍘' => ' mí', + '䍱' => ' xú', + '䍳' => ' què', + '䎌' => ' chù', + '䎁' => ' hú', + '䎋' => ' kào', + '䎊' => ' luò', + '䎉' => ' xù', + '䎈' => ' yì', + '䎇' => ' zhōu', + '䎆' => ' liào', + '䎅' => ' pò', + '䎄' => ' xiāo', + '䎃' => ' rǎn', + '䎂' => ' bǎo', + '䎀' => ' xuè', + '䍴' => ' wěi', + '䍿' => ' huáng', + '䍾' => ' yǎn', + '䍽' => ' lì', + '䍼' => ' zān', + '䍻' => ' xuàn', + '䍺' => ' huàn', + '䍸' => ' bó', + '䍷' => ' wěi', + '䍶' => ' dōng', + '䍵' => ' zhēng', + '䏄' => ' dǐ', + '䏆' => ' cáo', + '䐯' => ' léi', + '䐊' => ' kūn', + '䐔' => ' bǐn', + '䐓' => ' róu', + '䐒' => ' zhā', + '䐑' => ' zhé', + '䐐' => ' qiū', + '䐏' => ' chǔn', + '䐎' => ' dī', + '䐍' => ' chù', + '䐌' => ' tiǎn', + '䐋' => ' cōng', + '䐉' => ' zì', + '䐖' => ' xī', + '䐈' => ' zhí', + '䐇' => ' wěn', + '䐆' => ' cǎi', + '䐅' => ' xī', + '䐄' => ' xiàn', + '䐃' => ' jùn', + '䐂' => ' lù', + '䐁' => ' zhuó', + '䐀' => ' jì', + '䏿' => ' qǐ', + '䐕' => ' jí', + '䐗' => ' zhū', + '䏼' => ' cán', + '䐤' => ' chāi', + '䐮' => ' chǎn', + '䐭' => ' zhì', + '䐬' => ' cáo', + '䐫' => ' cōng', + '䐪' => ' fàn', + '䐩' => ' gāi', + '䐨' => ' gǔ', + '䐧' => ' kào', + '䐦' => ' kē', + '䐥' => ' wěng', + '䐣' => ' sǔn', + '䐘' => ' jué', + '䐢' => ' zhù', + '䐡' => ' qí', + '䐠' => ' huǎng', + '䐟' => ' xiǎng', + '䐞' => ' ruò', + '䐝' => ' suò', + '䐜' => ' chēn', + '䐛' => ' dā', + '䐚' => ' jī', + '䐙' => ' gé', + '䏽' => ' bù', + '䏻' => ' néng', + '䏇' => ' piào', + '䏓' => ' guǎn', + '䏝' => ' zhuān', + '䏜' => ' hē', + '䏛' => ' chǔn', + '䏚' => ' chǎo', + '䏙' => ' tǎn', + '䏘' => ' pì', + '䏗' => ' gài', + '䏖' => ' zhèn', + '䏕' => ' rèn', + '䏔' => ' niǔ', + '䏒' => ' piàn', + '䏟' => ' bié', + '䏑' => ' dì', + '䏐' => ' jué', + '䏏' => ' xū', + '䏎' => ' féng', + '䏍' => ' yuàn', + '䏌' => ' qì', + '䏋' => ' sù', + '䏊' => ' lóng', + '䏉' => ' shī', + '䏈' => ' lián', + '䏞' => ' mò', + '䏠' => ' qì', + '䏺' => ' pāng', + '䏯' => ' zhì', + '䏹' => ' xiàn', + '䏸' => ' yú', + '䏷' => ' hàn', + '䏶' => ' bì', + '䏵' => ' měng', + '䏴' => ' shào', + '䏳' => ' zhè', + '䏲' => ' dié', + '䏱' => ' jú', + '䏰' => ' rùn', + '䏮' => ' xí', + '䏡' => ' shì', + '䏬' => ' móu', + '䏫' => ' xiū', + '䏪' => ' èr', + '䏩' => ' xī', + '䏨' => ' huǐ', + '䏧' => ' nà', + '䏦' => ' guā', + '䏤' => ' sì', + '䏣' => ' jué', + '䏢' => ' bǐ', + '䔘' => ' zuò', + '䔚' => ' chún', + '䛨' => ' xìn', + '䙌' => ' kuì', + '䙘' => ' chǔ', + '䙗' => ' tì', + '䙕' => ' zǒng', + '䙔' => ' ōu', + '䙓' => ' bǎi', + '䙒' => ' xù', + '䙑' => ' cuī', + '䙐' => ' kè', + '䙏' => ' bó', + '䙎' => ' xié', + '䙊' => ' xiè', + '䙚' => ' niǎo', + '䙉' => ' xún', + '䙈' => ' hóu', + '䙇' => ' ruán', + '䙆' => ' kuì', + '䙅' => ' yāo', + '䙄' => ' qì', + '䙃' => ' duò', + '䙁' => ' cán', + '䙀' => ' běng', + '䘿' => ' jué', + '䙙' => ' chí', + '䙛' => ' guàn', + '䘽' => ' ní', + '䙩' => ' méng', + '䙸' => ' dé', + '䙷' => ' dé', + '䙵' => ' xī', + '䙳' => ' biāo', + '䙱' => ' dú', + '䙰' => ' lí', + '䙯' => ' cù', + '䙮' => ' guàn', + '䙬' => ' yìng', + '䙪' => ' lóng', + '䙨' => ' guǒ', + '䙜' => ' féng', + '䙦' => ' méng', + '䙥' => ' líng', + '䙤' => ' duǒ', + '䙣' => ' sà', + '䙢' => ' zèng', + '䙡' => ' kuì', + '䙠' => ' jué', + '䙟' => ' wéi', + '䙞' => ' dēng', + '䙝' => ' xiè', + '䘾' => ' guǎn', + '䘼' => ' wǎn', + '䙺' => ' lián', + '䘍' => ' chài', + '䘙' => ' wèi', + '䘘' => ' yù', + '䘕' => ' háng', + '䘔' => ' kā', + '䘓' => ' kàn', + '䘒' => ' zuī', + '䘑' => ' mài', + '䘐' => ' nǜ', + '䘏' => ' xù', + '䘎' => ' wān', + '䘌' => ' nì', + '䘝' => ' yì', + '䘋' => ' jiān', + '䘊' => ' miè', + '䘉' => ' cán', + '䘈' => ' lì', + '䘇' => ' wén', + '䘆' => ' xiǎn', + '䘅' => ' nái', + '䘄' => ' zhù', + '䘃' => ' mò', + '䘁' => ' gé', + '䘚' => ' zhú', + '䘟' => ' diāo', + '䘻' => ' yù', + '䘭' => ' zhì', + '䘺' => ' zhàn', + '䘹' => ' zuì', + '䘸' => ' yì', + '䘷' => ' biē', + '䘶' => ' hān', + '䘵' => ' lù', + '䘳' => ' jīn', + '䘱' => ' yù', + '䘰' => ' shān', + '䘮' => ' sāng', + '䘬' => ' róng', + '䘠' => ' fú', + '䘫' => ' nòu', + '䘪' => ' chōng', + '䘩' => ' xún', + '䘨' => ' jiǎo', + '䘦' => ' ní', + '䘥' => ' xiá', + '䘤' => ' shù', + '䘣' => ' zǐ', + '䘢' => ' zhǔ', + '䘡' => ' bǐ', + '䙹' => ' xiàn', + '䙼' => ' shào', + '䗿' => ' níng', + '䛂' => ' yāo', + '䛌' => ' táo', + '䛋' => ' jì', + '䛊' => ' xī', + '䛉' => ' miàn', + '䛈' => ' shì', + '䛇' => ' yuǎn', + '䛆' => ' zhòu', + '䛅' => ' xiá', + '䛄' => ' yuǎn', + '䛃' => ' wàn', + '䛁' => ' nán', + '䛎' => ' xuè', + '䛀' => ' fǎn', + '䚿' => ' yìn', + '䚾' => ' nín', + '䚽' => ' hào', + '䚼' => ' nǜ', + '䚻' => ' yáo', + '䚺' => ' yáo', + '䚹' => ' pǐ', + '䚸' => ' xiè', + '䚷' => ' yī', + '䛍' => ' fèi', + '䛏' => ' ní', + '䚵' => ' tǒu', + '䛝' => ' náo', + '䛧' => ' mí', + '䛦' => ' sòng', + '䛥' => ' xī', + '䛤' => ' cù', + '䛣' => ' pīng', + '䛢' => ' tū', + '䛡' => ' huà', + '䛠' => ' dòu', + '䛟' => ' jiá', + '䛞' => ' hàn', + '䛜' => ' xùn', + '䛐' => ' cí', + '䛛' => ' huì', + '䛚' => ' lüè', + '䛙' => ' xù', + '䛘' => ' rén', + '䛗' => ' zhǐ', + '䛖' => ' è', + '䛕' => ' yù', + '䛔' => ' ná', + '䛒' => ' biàn', + '䛑' => ' mì', + '䚶' => ' tiān', + '䚴' => ' wà', + '䙽' => ' xié', + '䚋' => ' yùn', + '䚗' => ' gāng', + '䚖' => ' líng', + '䚕' => ' lì', + '䚔' => ' bīn', + '䚓' => ' niǎn', + '䚒' => ' chuáng', + '䚑' => ' mái', + '䚐' => ' jí', + '䚏' => ' lìn', + '䚍' => ' qì', + '䚊' => ' jiǎn', + '䚙' => ' xuān', + '䚉' => ' qì', + '䚈' => ' juàn', + '䚇' => ' shěng', + '䚆' => ' yǐng', + '䚅' => ' lài', + '䚄' => ' lù', + '䚃' => ' yóu', + '䚂' => ' hè', + '䙿' => ' wèi', + '䙾' => ' shī', + '䚘' => ' chéng', + '䚚' => ' xiǎn', + '䚳' => ' zhì', + '䚨' => ' fèi', + '䚲' => ' shàn', + '䚱' => ' xìn', + '䚰' => ' pǐ', + '䚯' => ' tǎo', + '䚮' => ' réng', + '䚭' => ' xuān', + '䚬' => ' lín', + '䚫' => ' xí', + '䚪' => ' guān', + '䚩' => ' jiǎo', + '䚧' => ' liú', + '䚛' => ' hú', + '䚦' => ' zhì', + '䚥' => ' nuò', + '䚣' => ' tí', + '䚢' => ' chè', + '䚡' => ' sāi', + '䚠' => ' hùn', + '䚟' => ' dǎi', + '䚞' => ' dǎi', + '䚝' => ' zú', + '䚜' => ' bī', + '䘀' => ' fù', + '䗾' => ' xiǎn', + '䔛' => ' qǐng', + '䕦' => ' yíng', + '䕱' => ' tóu', + '䕰' => ' fán', + '䕯' => ' piáo', + '䕮' => ' jú', + '䕭' => ' qián', + '䕫' => ' kuí', + '䕪' => ' zé', + '䕩' => ' lǎo', + '䕨' => ' téng', + '䕧' => ' xiào', + '䕥' => ' nǐ', + '䕳' => ' mí', + '䕤' => ' jī', + '䕣' => ' hé', + '䕢' => ' zhǎ', + '䕡' => ' lǘ', + '䕠' => ' fèi', + '䕟' => ' xīng', + '䕞' => ' làng', + '䕝' => ' chēng', + '䕛' => ' jiá', + '䕚' => ' kuì', + '䕲' => ' lǐn', + '䕴' => ' zhuó', + '䕘' => ' líng', + '䖂' => ' luán', + '䖍' => ' qián', + '䖌' => ' yì', + '䖋' => ' nüè', + '䖊' => ' yì', + '䖈' => ' nüè', + '䖇' => ' yù', + '䖆' => ' niàng', + '䖅' => ' líng', + '䖄' => ' rán', + '䖃' => ' yuè', + '䖁' => ' yì', + '䕵' => ' xié', + '䕿' => ' hàn', + '䕾' => ' yín', + '䕽' => ' zhú', + '䕼' => ' rán', + '䕻' => ' lì', + '䕺' => ' cóng', + '䕹' => ' zá', + '䕸' => ' jiē', + '䕷' => ' mí', + '䕶' => ' hù', + '䕙' => ' jié', + '䕗' => ' bì', + '䖏' => ' chǔ', + '䔬' => ' yì', + '䔷' => ' qín', + '䔶' => ' tí', + '䔴' => ' cè', + '䔳' => ' rán', + '䔲' => ' dēng', + '䔱' => ' yī', + '䔰' => ' fù', + '䔯' => ' kù', + '䔮' => ' sī', + '䔭' => ' nìng', + '䔪' => ' shuǎng', + '䔹' => ' suì', + '䔧' => ' lí', + '䔤' => ' pā', + '䔣' => ' lí', + '䔢' => ' huá', + '䔡' => ' yú', + '䔠' => ' shǎo', + '䔟' => ' yí', + '䔞' => ' lǜ', + '䔝' => ' zhāi', + '䔜' => ' nán', + '䔸' => ' biǎo', + '䔺' => ' wéi', + '䕕' => ' màn', + '䕉' => ' zé', + '䕔' => ' xián', + '䕓' => ' chá', + '䕒' => ' jiā', + '䕑' => ' jùn', + '䕏' => ' é', + '䕎' => ' fú', + '䕍' => ' yì', + '䕌' => ' zhì', + '䕋' => ' táng', + '䕊' => ' tán', + '䕈' => ' xiè', + '䔻' => ' dūn', + '䕇' => ' huì', + '䕆' => ' dòu', + '䕅' => ' sǎo', + '䕃' => ' yìn', + '䕁' => ' fěi', + '䕀' => ' kuǎn', + '䔿' => ' zǔn', + '䔾' => ' qì', + '䔽' => ' ài', + '䔼' => ' sè', + '䖎' => ' xiá', + '䖐' => ' yín', + '䗽' => ' wèi', + '䗔' => ' hóu', + '䗞' => ' cán', + '䗝' => ' cán', + '䗜' => ' liú', + '䗛' => ' xiū', + '䗚' => ' bó', + '䗙' => ' hán', + '䗘' => ' gé', + '䗗' => ' jī', + '䗖' => ' dì', + '䗕' => ' wǎn', + '䗓' => ' cōng', + '䗠' => ' xuán', + '䗒' => ' bìng', + '䗑' => ' yì', + '䗐' => ' shī', + '䗏' => ' sōu', + '䗎' => ' yān', + '䗍' => ' lǐ', + '䗌' => ' xīng', + '䗋' => ' móu', + '䗊' => ' tàn', + '䗉' => ' chāng', + '䗟' => ' yì', + '䗡' => ' yán', + '䗇' => ' jú', + '䗱' => ' pú', + '䗼' => ' xūn', + '䗻' => ' jié', + '䗺' => ' yǎn', + '䗹' => ' cì', + '䗸' => ' yōng', + '䗷' => ' yì', + '䗶' => ' là', + '䗵' => ' jiāng', + '䗴' => ' tíng', + '䗲' => ' lìn', + '䗰' => ' guàn', + '䗢' => ' zǎo', + '䗯' => ' jìn', + '䗮' => ' shuǎng', + '䗫' => ' má', + '䗪' => ' zhè', + '䗩' => ' qī', + '䗨' => ' yú', + '䗧' => ' kāng', + '䗥' => ' zōng', + '䗤' => ' yóng', + '䗣' => ' hàn', + '䗈' => ' méng', + '䗆' => ' guǎn', + '䖑' => ' mì', + '䖝' => ' chóng', + '䖧' => ' nà', + '䖦' => ' qū', + '䖥' => ' lí', + '䖤' => ' wǎn', + '䖣' => ' zǎo', + '䖢' => ' miáo', + '䖡' => ' nǜ', + '䖠' => ' yuán', + '䖟' => ' mǎng', + '䖞' => ' zhǒu', + '䖜' => ' yín', + '䖩' => ' bì', + '䖛' => ' suǒ', + '䖚' => ' wū', + '䖙' => ' tī', + '䖘' => ' tú', + '䖗' => ' yán', + '䖖' => ' xiá', + '䖕' => ' zǔ', + '䖔' => ' kǎn', + '䖓' => ' nà', + '䖒' => ' xī', + '䖨' => ' shí', + '䖪' => ' zī', + '䗅' => ' cháng', + '䖹' => ' yáng', + '䗄' => ' fǔ', + '䗃' => ' zhàn', + '䗂' => ' hǔ', + '䗁' => ' jì', + '䗀' => ' chēng', + '䖿' => ' lí', + '䖽' => ' lí', + '䖼' => ' jué', + '䖻' => ' yóu', + '䖺' => ' tiáo', + '䖸' => ' é', + '䖫' => ' bàng', + '䖷' => ' xī', + '䖶' => ' huī', + '䖵' => ' kūn', + '䖴' => ' yáo', + '䖳' => ' zhà', + '䖲' => ' xún', + '䖱' => ' kuāng', + '䖰' => ' pài', + '䖯' => ' kuí', + '䖮' => ' xiǎng', + '䖭' => ' juàn', + '䪀' => ' guǎn', + '䪂' => ' gé', + '䍖' => ' fú', + '佚' => ' yì', + '佤' => ' wǎ', + '佣' => ' yōng', + '佢' => ' qú', + '佡' => ' xiān', + '你' => ' nǐ', + '佟' => ' tóng', + '佞' => ' nìng', + '佝' => ' gōu', + '作' => ' zuò', + '佛' => ' fú', + '余' => ' yú', + '佦' => ' shi', + '佘' => ' shé', + '佗' => ' tuó', + '佖' => ' bì', + '何' => ' hé', + '佔' => ' zhàn', + '体' => ' tǐ', + '佒' => ' yǎng', + '佑' => ' yòu', + '佐' => ' zuǒ', + '住' => ' zhù', + '佥' => ' qiān', + '佧' => ' kǎ', + '位' => ' wèi', + '佴' => ' èr', + '佾' => ' yì', + '佽' => ' cì', + '佼' => ' jiǎo', + '佻' => ' tiāo', + '佺' => ' quán', + '佹' => ' guǐ', + '佸' => ' huó', + '佷' => ' hěn', + '佶' => ' jí', + '併' => ' bìng', + '佳' => ' jiā', + '佨' => ' bao', + '佲' => ' mǐng', + '佱' => ' fǎ', + '佰' => ' bǎi', + '佯' => ' yáng', + '佮' => ' gé', + '佭' => ' xiáng', + '佬' => ' lǎo', + '佫' => ' hè', + '佪' => ' huí', + '佩' => ' pèi', + '低' => ' dī', + '佌' => ' cǐ', + '侀' => ' xíng', + '伦' => ' lún', + '估' => ' gū', + '伯' => ' bó', + '伮' => ' nǔ', + '伭' => ' xián', + '伬' => ' ze', + '伫' => ' zhù', + '伪' => ' wěi', + '伩' => ' xìn', + '伨' => ' xùn', + '伧' => ' cāng', + '伥' => ' chāng', + '伲' => ' nì', + '伤' => ' shāng', + '伣' => ' xiàn', + '伢' => ' yá', + '伡' => ' chē', + '传' => ' chuán', + '伟' => ' wěi', + '伞' => ' sǎn', + '伝' => ' chuán', + '伜' => ' cuì', + '伛' => ' yǔ', + '伱' => ' nǐ', + '伳' => ' xiè', + '佋' => ' zhāo', + '佀' => ' sì', + '佊' => ' bǐ', + '佉' => ' qū', + '佈' => ' bù', + '佇' => ' zhù', + '但' => ' dàn', + '佅' => ' mài', + '佄' => ' hān', + '佃' => ' diàn', + '佂' => ' zhēng', + '佁' => ' yǐ', + '伿' => ' yì', + '伴' => ' bàn', + '伾' => ' pī', + '伽' => ' jiā', + '似' => ' shì', + '伻' => ' bēng', + '伺' => ' cì', + '伹' => ' qū', + '伸' => ' shēn', + '伷' => ' zhòu', + '伶' => ' líng', + '伵' => ' xù', + '使' => ' shǐ', + '侁' => ' shēn', + '伙' => ' huǒ', + '係' => ' xì', + '俌' => ' fǔ', + '俋' => ' yì', + '俊' => ' jùn', + '俉' => ' wǔ', + '俈' => ' kù', + '俇' => ' guàng', + '俆' => ' xú', + '俅' => ' qiú', + '俄' => ' é', + '促' => ' cù', + '俁' => ' yǔ', + '俎' => ' zǔ', + '俀' => ' tuǐ', + '便' => ' biàn', + '侾' => ' xiāo', + '侽' => ' nán', + '侼' => ' bó', + '侻' => ' tuì', + '侺' => ' shèn', + '侹' => ' tǐng', + '侸' => ' shù', + '侷' => ' jú', + '俍' => ' liáng', + '俏' => ' qiào', + '侵' => ' qīn', + '俜' => ' pīng', + '俦' => ' chóu', + '俥' => ' chē', + '俤' => ' dì', + '俣' => ' yǔ', + '俢' => ' xiū', + '信' => ' xìn', + '俠' => ' xiá', + '俟' => ' qí', + '俞' => ' yú', + '保' => ' bǎo', + '俛' => ' fǔ', + '俐' => ' lì', + '俚' => ' lǐ', + '俙' => ' xī', + '俘' => ' fú', + '俗' => ' sú', + '俖' => ' pěi', + '俕' => ' sàn', + '俔' => ' qiàn', + '俓' => ' jìng', + '俒' => ' hùn', + '俑' => ' yǒng', + '侶' => ' lǚ', + '侴' => ' chǒu', + '侂' => ' tuō', + '侎' => ' mǐ', + '侘' => ' chà', + '侗' => ' dòng', + '侖' => ' lún', + '侕' => ' ér', + '侔' => ' móu', + '侓' => ' lù', + '侒' => ' ān', + '侑' => ' yòu', + '侐' => ' xù', + '侏' => ' zhū', + '侍' => ' shì', + '侚' => ' xùn', + '侌' => ' yīn', + '例' => ' lì', + '侊' => ' guāng', + '侉' => ' kuǎ', + '侈' => ' chǐ', + '侇' => ' yí', + '來' => ' lái', + '侅' => ' gāi', + '侄' => ' zhí', + '侃' => ' kǎn', + '侙' => ' chī', + '供' => ' gōng', + '侳' => ' zuò', + '侨' => ' qiáo', + '侲' => ' zhèn', + '侱' => ' chěng', + '侰' => ' jiǒng', + '侯' => ' hóu', + '侮' => ' wǔ', + '侭' => ' jǐn', + '侬' => ' nóng', + '侫' => ' nìng', + '侪' => ' chái', + '侩' => ' kuài', + '侧' => ' cè', + '侜' => ' zhōu', + '侦' => ' zhēn', + '侥' => ' jiǎo', + '侤' => ' ta', + '侣' => ' lǚ', + '侢' => ' zài', + '価' => ' sì', + '侠' => ' xiá', + '侟' => ' cún', + '侞' => ' rú', + '依' => ' yī', + '会' => ' huì', + '优' => ' yōu', + '俨' => ' yǎn', + '亊' => ' shì', + '五' => ' wǔ', + '亓' => ' qí', + '互' => ' hù', + '云' => ' yún', + '亐' => ' yú', + '亏' => ' kuī', + '于' => ' yú', + '亍' => ' chù', + '二' => ' èr', + '事' => ' shì', + '争' => ' zhēng', + '亖' => ' sì', + '予' => ' yǔ', + '亇' => ' ma', + '了' => ' le', + '亅' => ' jué', + '亄' => ' yì', + '亃' => ' lǐn', + '亂' => ' luàn', + '亁' => ' gān', + '亀' => ' guī', + '乿' => ' zhì', + '井' => ' jǐng', + '亗' => ' suì', + '乽' => ' zhě', + '交' => ' jiāo', + '亮' => ' liàng', + '亭' => ' tíng', + '京' => ' jīng', + '享' => ' xiǎng', + '亪' => ' ye', + '亩' => ' mǔ', + '亨' => ' hēng', + '产' => ' chǎn', + '亦' => ' yì', + '亥' => ' hài', + '亣' => ' tà', + '亘' => ' gèn', + '亢' => ' kàng', + '亡' => ' wáng', + '亠' => ' tóu', + '亟' => ' jí', + '亞' => ' yà', + '亝' => ' qí', + '亜' => ' yà', + '些' => ' xiē', + '亚' => ' yà', + '亙' => ' gèn', + '乾' => ' gān', + '乼' => ' cui', + '亰' => ' jīng', + '乖' => ' guāi', + '习' => ' xí', + '也' => ' yě', + '乞' => ' qǐ', + '九' => ' jiǔ', + '乜' => ' miē', + '乛' => ' ya', + '乚' => ' yǐn', + '乙' => ' yǐ', + '乘' => ' chéng', + '乗' => ' chéng', + '乕' => ' hǔ', + '乢' => ' gài', + '乔' => ' qiáo', + '乓' => ' pāng', + '乒' => ' pīng', + '乑' => ' yín', + '乐' => ' lè', + '乏' => ' fá', + '乎' => ' hū', + '乍' => ' zhà', + '乌' => ' wū', + '之' => ' zhī', + '乡' => ' xiāng', + '乣' => ' jiǔ', + '乻' => ' yú', + '买' => ' mǎi', + '乺' => ' suǒ', + '乹' => ' gān', + '乸' => ' nǎ', + '乷' => ' shā', + '乶' => ' fǔ', + '乵' => ' yǎn', + '乴' => ' xué', + '乳' => ' rǔ', + '乲' => ' zī', + '乱' => ' luàn', + '乯' => ' hū', + '乤' => ' xià', + '乮' => ' mǎo', + '乭' => ' shí', + '乬' => ' jù', + '乫' => ' jiā', + '乪' => ' náng', + '乩' => ' jī', + '乨' => ' shǐ', + '乧' => ' dou', + '书' => ' shū', + '乥' => ' hù', + '亯' => ' xiǎng', + '亱' => ' yè', + '众' => ' zhòng', + '仲' => ' zhòng', + '仼' => ' wáng', + '任' => ' rèn', + '仺' => ' cāng', + '仹' => ' fēng', + '仸' => ' yǎo', + '价' => ' jià', + '件' => ' jiàn', + '仵' => ' wǔ', + '仴' => ' wò', + '仳' => ' pǐ', + '仱' => ' qián', + '仾' => ' dī', + '仰' => ' yǎng', + '仯' => ' chào', + '仮' => ' jiǎ', + '仭' => ' rèn', + '们' => ' men', + '仫' => ' mù', + '仪' => ' yí', + '仩' => ' shang', + '仨' => ' sā', + '仧' => ' cháng', + '份' => ' fèn', + '仿' => ' fǎng', + '以' => ' yǐ', + '伌' => ' ài', + '伖' => ' tǎng', + '伕' => ' fū', + '伔' => ' dǎn', + '伓' => ' pī', + '伒' => ' jìn', + '休' => ' xiū', + '伐' => ' fá', + '伏' => ' fú', + '伎' => ' jì', + '伍' => ' wǔ', + '伋' => ' jí', + '伀' => ' zhōng', + '伊' => ' yī', + '伉' => ' kàng', + '伈' => ' xǐn', + '伇' => ' yì', + '伆' => ' wù', + '伅' => ' dùn', + '伄' => ' diào', + '伃' => ' yú', + '伂' => ' pèi', + '企' => ' qǐ', + '仦' => ' chào', + '令' => ' lìng', + '亲' => ' qīn', + '亾' => ' wáng', + '仈' => ' bā', + '仇' => ' chóu', + '仆' => ' pū', + '仅' => ' jǐn', + '仄' => ' zè', + '仃' => ' dīng', + '仂' => ' lè', + '仁' => ' rén', + '什' => ' shén', + '亿' => ' yì', + '亽' => ' ji', + '今' => ' jīn', + '亼' => ' jí', + '亻' => ' rén', + '人' => ' rén', + '亹' => ' mén', + '亸' => ' duǒ', + '亷' => ' lián', + '亶' => ' dǎn', + '亵' => ' xiè', + '亴' => ' yòu', + '亳' => ' bó', + '仉' => ' zhǎng', + '介' => ' jiè', + '代' => ' dài', + '付' => ' fù', + '仢' => ' bó', + '仡' => ' gē', + '仠' => ' gǎn', + '仟' => ' qiān', + '仞' => ' rèn', + '仝' => ' tóng', + '仜' => ' hóng', + '仛' => ' tuō', + '仚' => ' xiān', + '仙' => ' xiān', + '仗' => ' zhàng', + '仌' => ' bīng', + '他' => ' tā', + '仕' => ' shì', + '仔' => ' zǐ', + '仓' => ' cāng', + '仒' => ' bīng', + '仑' => ' lún', + '仐' => ' sǎn', + '仏' => ' fó', + '从' => ' cóng', + '仍' => ' réng', + '俧' => ' zhi', + '俩' => ' liǎ', + '义' => ' yì', + '僻' => ' pì', + '儅' => ' dàng', + '億' => ' yì', + '儃' => ' chán', + '儂' => ' nóng', + '儁' => ' jùn', + '儀' => ' yí', + '僿' => ' sài', + '僾' => ' ài', + '僽' => ' zhòu', + '僼' => ' fēng', + '僺' => ' qiào', + '儇' => ' xuān', + '價' => ' jià', + '僸' => ' jìn', + '僷' => ' yè', + '僶' => ' mǐn', + '僵' => ' jiāng', + '僴' => ' xiàn', + '僳' => ' sù', + '僲' => ' xian', + '僱' => ' gù', + '僰' => ' bó', + '儆' => ' jǐng', + '儈' => ' kuài', + '僮' => ' tóng', + '儕' => ' chái', + '償' => ' cháng', + '儞' => ' nǐ', + '儝' => ' qióng', + '儜' => ' níng', + '儛' => ' wǔ', + '儚' => ' méng', + '儙' => ' qiàn', + '儘' => ' jǐn', + '儗' => ' nǐ', + '儖' => ' lán', + '儔' => ' chóu', + '儉' => ' jiǎn', + '儓' => ' tái', + '儒' => ' rú', + '儑' => ' án', + '儐' => ' bīn', + '儏' => ' can', + '儎' => ' zài', + '儍' => ' shǎ', + '儌' => ' jiǎo', + '儋' => ' dān', + '儊' => ' chù', + '僯' => ' lìn', + '僭' => ' jiàn', + '儡' => ' lěi', + '僇' => ' lù', + '僑' => ' qiáo', + '僐' => ' shàn', + '像' => ' xiàng', + '僎' => ' zhuàn', + '働' => ' dòng', + '僌' => ' yíng', + '僋' => ' tàn', + '僊' => ' xiān', + '僉' => ' qiān', + '僈' => ' mán', + '僆' => ' liàn', + '僓' => ' tuǐ', + '僅' => ' jǐn', + '僄' => ' piào', + '僃' => ' bèi', + '僂' => ' lóu', + '僁' => ' xiè', + '僀' => ' dì', + '傿' => ' yàn', + '傾' => ' qīng', + '傽' => ' zhāng', + '傼' => ' hàn', + '僒' => ' jiǒng', + '僔' => ' zǔn', + '僬' => ' jiāo', + '僡' => ' huì', + '僫' => ' è', + '僪' => ' jú', + '僩' => ' xiàn', + '僨' => ' fèn', + '僧' => ' sēng', + '僦' => ' jiù', + '僥' => ' jiǎo', + '僤' => ' dàn', + '僣' => ' tiě', + '僢' => ' chuǎn', + '僠' => ' bō', + '僕' => ' pú', + '僟' => ' jī', + '僞' => ' wěi', + '僝' => ' chán', + '僜' => ' chēng', + '僛' => ' qī', + '僚' => ' liáo', + '僙' => ' guāng', + '僘' => ' chǎng', + '僗' => ' láo', + '僖' => ' xī', + '儠' => ' liè', + '儢' => ' lǚ', + '傺' => ' chì', + '入' => ' rù', + '兯' => ' han', + '兮' => ' xī', + '六' => ' liù', + '公' => ' gōng', + '八' => ' bā', + '兪' => ' yú', + '兩' => ' liǎng', + '全' => ' quán', + '內' => ' nèi', + '兦' => ' wáng', + '兤' => ' huáng', + '共' => ' gòng', + '兣' => ' lǐ', + '兢' => ' jīng', + '兠' => ' dōu', + '兟' => ' shēn', + '兞' => ' máo', + '兝' => ' fēn', + '兜' => ' dōu', + '兛' => ' qiān', + '党' => ' dǎng', + '兘' => ' shǐ', + '兰' => ' lán', + '兲' => ' tiān', + '兖' => ' yǎn', + '兿' => ' yì', + '冉' => ' rǎn', + '冈' => ' gāng', + '冇' => ' mǎo', + '円' => ' yuán', + '内' => ' nèi', + '冄' => ' rǎn', + '冃' => ' mào', + '冂' => ' jiōng', + '冁' => ' chǎn', + '冀' => ' jì', + '兾' => ' jì', + '关' => ' guān', + '兽' => ' shòu', + '兼' => ' jiān', + '养' => ' yǎng', + '兺' => ' fēn', + '兹' => ' zī', + '典' => ' diǎn', + '具' => ' jù', + '其' => ' qí', + '兵' => ' bīng', + '兴' => ' xìng', + '兗' => ' yǎn', + '兕' => ' sì', + '儣' => ' kuǎng', + '儯' => ' téng', + '儹' => ' zǎn', + '儸' => ' luó', + '儷' => ' lì', + '儶' => ' huì', + '儵' => ' shū', + '儴' => ' ráng', + '儳' => ' chán', + '儲' => ' chǔ', + '儱' => ' lǒng', + '儰' => ' wěi', + '儮' => ' lì', + '儻' => ' tǎng', + '儭' => ' chèn', + '儬' => ' chèn', + '儫' => ' háo', + '優' => ' yōu', + '儩' => ' sì', + '儨' => ' zhí', + '儧' => ' zǎn', + '儦' => ' biāo', + '儥' => ' yù', + '儤' => ' bào', + '儺' => ' nuó', + '儼' => ' yǎn', + '兔' => ' tù', + '光' => ' guāng', + '兓' => ' jīn', + '兒' => ' ér', + '兑' => ' duì', + '児' => ' ér', + '兏' => ' cháng', + '兎' => ' tù', + '免' => ' miǎn', + '兌' => ' duì', + '克' => ' kè', + '兊' => ' duì', + '先' => ' xiān', + '儽' => ' léi', + '兇' => ' xiōng', + '兆' => ' zhào', + '充' => ' chōng', + '兄' => ' xiōng', + '元' => ' yuán', + '兂' => ' zān', + '允' => ' yǔn', + '兀' => ' wù', + '儿' => ' ér', + '儾' => ' nàng', + '傻' => ' shǎ', + '傹' => ' jìng', + '俪' => ' lì', + '倪' => ' ní', + '倴' => ' bèn', + '倳' => ' zì', + '倲' => ' dōng', + '倱' => ' hùn', + '倰' => ' lèng', + '倯' => ' sōng', + '倮' => ' luǒ', + '倭' => ' wō', + '倬' => ' zhuō', + '倫' => ' lún', + '倩' => ' qiàn', + '倶' => ' jù', + '倨' => ' jù', + '倧' => ' zōng', + '倦' => ' juàn', + '倥' => ' kōng', + '値' => ' zhí', + '倣' => ' fǎng', + '倢' => ' jié', + '倡' => ' chàng', + '倠' => ' suī', + '借' => ' jiè', + '倵' => ' wǔ', + '倷' => ' nǎi', + '倝' => ' gàn', + '偄' => ' ruǎn', + '偎' => ' wēi', + '偍' => ' tí', + '偌' => ' ruò', + '偋' => ' bìng', + '偊' => ' yǔ', + '偉' => ' wěi', + '偈' => ' jì', + '假' => ' jiǎ', + '偆' => ' chǔn', + '偅' => ' zhòng', + '偃' => ' yǎn', + '倸' => ' cǎi', + '偂' => ' jiān', + '偁' => ' chēng', + '偀' => ' yīng', + '倿' => ' qie', + '倾' => ' qīng', + '倽' => ' shà', + '值' => ' zhí', + '倻' => ' yē', + '债' => ' zhài', + '倹' => ' jiǎn', + '倞' => ' jìng', + '倜' => ' tì', + '偐' => ' yàn', + '俶' => ' chù', + '倀' => ' chāng', + '俿' => ' hǔ', + '俾' => ' bǐ', + '俽' => ' xīn', + '俼' => ' yù', + '俻' => ' bèi', + '俺' => ' ǎn', + '俹' => ' yà', + '俸' => ' fèng', + '俷' => ' fèi', + '俵' => ' biào', + '倂' => ' bìng', + '俴' => ' jiàn', + '俳' => ' pái', + '俲' => ' xiào', + '俱' => ' jù', + '俰' => ' huò', + '俯' => ' fǔ', + '修' => ' xiū', + '俭' => ' jiǎn', + '俬' => ' sī', + '俫' => ' lái', + '倁' => ' zhī', + '倃' => ' jiù', + '倛' => ' qī', + '倐' => ' shū', + '倚' => ' yǐ', + '候' => ' hòu', + '倘' => ' tǎng', + '倗' => ' péng', + '倖' => ' xìng', + '倕' => ' chuí', + '倔' => ' jué', + '倓' => ' tán', + '倒' => ' dào', + '們' => ' men', + '倏' => ' shū', + '倄' => ' yáo', + '倎' => ' tiǎn', + '倍' => ' bèi', + '倌' => ' guān', + '個' => ' gè', + '倊' => ' zòng', + '倉' => ' cāng', + '倈' => ' lái', + '倇' => ' wǎn', + '倆' => ' liǎ', + '倅' => ' cuì', + '偏' => ' piān', + '偑' => ' fēng', + '傸' => ' chuǎng', + '傓' => ' shàn', + '傝' => ' tàn', + '傜' => ' yáo', + '傛' => ' yǒng', + '傚' => ' xiào', + '備' => ' bèi', + '傘' => ' sǎn', + '傗' => ' chù', + '傖' => ' cāng', + '傕' => ' jué', + '傔' => ' qiàn', + '傒' => ' xī', + '傟' => ' yǎng', + '傑' => ' jié', + '傐' => ' hào', + '傏' => ' táng', + '傎' => ' diān', + '傍' => ' bàng', + '傌' => ' mà', + '傋' => ' jiǎng', + '傊' => ' yùn', + '傉' => ' nù', + '傈' => ' lì', + '傞' => ' suō', + '傠' => ' fā', + '傆' => ' yuàn', + '傭' => ' yōng', + '傷' => ' shāng', + '傶' => ' zú', + '債' => ' zhài', + '傴' => ' yǔ', + '傳' => ' chuán', + '傲' => ' ào', + '傱' => ' sǒng', + '傰' => ' bēng', + '傯' => ' zǒng', + '傮' => ' zāo', + '催' => ' cuī', + '傡' => ' bìng', + '傫' => ' lěi', + '傪' => ' cān', + '傩' => ' nuó', + '储' => ' chǔ', + '傧' => ' bīn', + '傦' => ' gu', + '傥' => ' tǎng', + '傤' => ' zài', + '傣' => ' dǎi', + '傢' => ' jiā', + '傇' => ' rǒng', + '傅' => ' fù', + '偒' => ' tǎng', + '偞' => ' xiè', + '偨' => ' cī', + '偧' => ' zhā', + '偦' => ' xǔ', + '健' => ' jiàn', + '偤' => ' yóu', + '偣' => ' yān', + '偢' => ' chǒu', + '偡' => ' zhàn', + '偠' => ' yǎo', + '偟' => ' huáng', + '偝' => ' bèi', + '偪' => ' bī', + '停' => ' tíng', + '偛' => ' chā', + '做' => ' zuò', + '偙' => ' dì', + '偘' => ' kǎn', + '偗' => ' shěng', + '偖' => ' chě', + '偕' => ' xié', + '偔' => ' è', + '偓' => ' wò', + '偩' => ' fù', + '偫' => ' zhì', + '傄' => ' xiā', + '偹' => ' bèi', + '傃' => ' sù', + '傂' => ' zhì', + '傁' => ' sǒu', + '傀' => ' guī', + '偿' => ' cháng', + '偾' => ' fèn', + '偽' => ' wěi', + '偼' => ' jié', + '偻' => ' lóu', + '偺' => ' zá', + '偸' => ' tōu', + '偬' => ' zǒng', + '偷' => ' tōu', + '偶' => ' ǒu', + '偵' => ' zhēn', + '側' => ' cè', + '偳' => ' duān', + '偲' => ' cāi', + '偱' => ' xún', + '偰' => ' xiè', + '偯' => ' yǐ', + '偮' => ' jí', + '偭' => ' miǎn', + '乊' => ' yī', + '么' => ' me', + '䪃' => ' dūn', + '䮬' => ' mò', + '䮷' => ' dú', + '䮵' => ' tóng', + '䮴' => ' dèng', + '䮳' => ' fán', + '䮲' => ' huáng', + '䮱' => ' zhú', + '䮰' => ' zhé', + '䮯' => ' ào', + '䮮' => ' mài', + '䮭' => ' mì', + '䮫' => ' lóu', + '䮹' => ' wèi', + '䮪' => ' chéng', + '䮩' => ' gú', + '䮨' => ' zǎi', + '䮧' => ' hàn', + '䮥' => ' lì', + '䮤' => ' hé', + '䮢' => ' zhá', + '䮡' => ' bì', + '䮠' => ' bī', + '䮟' => ' sōu', + '䮸' => ' wò', + '䮺' => ' jì', + '䮝' => ' hún', + '䯈' => ' wán', + '䯒' => ' héng', + '䯑' => ' kuāng', + '䯐' => ' hái', + '䯏' => ' guā', + '䯎' => ' gàn', + '䯍' => ' líng', + '䯌' => ' kāo', + '䯋' => ' bó', + '䯊' => ' qià', + '䯉' => ' wā', + '䯇' => ' kū', + '䮻' => ' chì', + '䯆' => ' yì', + '䯅' => ' niè', + '䯄' => ' guā', + '䯂' => ' shēn', + '䯁' => ' luó', + '䯀' => ' niè', + '䮿' => ' jiǎn', + '䮾' => ' lóng', + '䮽' => ' biāo', + '䮼' => ' lín', + '䮞' => ' chǔn', + '䮜' => ' zhá', + '䯔' => ' zé', + '䭱' => ' bié', + '䭻' => ' fù', + '䭺' => ' ǎng', + '䭹' => ' áng', + '䭸' => ' bǎo', + '䭷' => ' máo', + '䭶' => ' qí', + '䭵' => ' fán', + '䭴' => ' huán', + '䭳' => ' wèi', + '䭲' => ' yǐ', + '䭰' => ' bèng', + '䭽' => ' qún', + '䭯' => ' bó', + '䭮' => ' fú', + '䭭' => ' shǒu', + '䭬' => ' qǐ', + '䭫' => ' qǐ', + '䭪' => ' liáng', + '䭩' => ' mó', + '䭨' => ' shuì', + '䭧' => ' mǐ', + '䭦' => ' bō', + '䭼' => ' qí', + '䭾' => ' tuó', + '䮛' => ' fù', + '䮏' => ' wú', + '䮚' => ' lèng', + '䮙' => ' yù', + '䮘' => ' ér', + '䮗' => ' àn', + '䮖' => ' chāng', + '䮕' => ' zhuó', + '䮔' => ' zuī', + '䮓' => ' zhuō', + '䮒' => ' pū', + '䮑' => ' lèi', + '䮎' => ' xì', + '䭿' => ' yì', + '䮍' => ' niǎo', + '䮋' => ' lì', + '䮊' => ' yí', + '䮉' => ' lú', + '䮈' => ' chí', + '䮇' => ' yù', + '䮄' => ' xuán', + '䮂' => ' bá', + '䮁' => ' pián', + '䮀' => ' bó', + '䯓' => ' kuī', + '䯕' => ' tīng', + '䭤' => ' qiǎn', + '䰛' => ' lì', + '䰥' => ' huò', + '䰤' => ' dōng', + '䰣' => ' wǎng', + '䰢' => ' xìng', + '䰡' => ' chì', + '䰠' => ' shén', + '䰟' => ' hún', + '䰞' => ' zhǔ', + '䰝' => ' zèng', + '䰜' => ' lì', + '䰚' => ' wén', + '䰧' => ' hū', + '䰙' => ' yǐ', + '䰘' => ' liú', + '䰖' => ' zuǎn', + '䰕' => ' lú', + '䰔' => ' pán', + '䰓' => ' mián', + '䰒' => ' méng', + '䰐' => ' lán', + '䰏' => ' jì', + '䰎' => ' kuì', + '䰦' => ' pǐ', + '䰨' => ' mèi', + '䰌' => ' zǒng', + '䰸' => ' gōng', + '䱂' => ' yǒu', + '䱁' => ' qiáo', + '䱀' => ' yāng', + '䰿' => ' tuó', + '䰾' => ' bā', + '䰽' => ' bèi', + '䰼' => ' qín', + '䰻' => ' yú', + '䰺' => ' jiè', + '䰹' => ' zé', + '䰷' => ' bàng', + '䰩' => ' chě', + '䰵' => ' zī', + '䰴' => ' qì', + '䰲' => ' yà', + '䰱' => ' líng', + '䰰' => ' rú', + '䰯' => ' yì', + '䰭' => ' nòu', + '䰬' => ' jú', + '䰫' => ' chāo', + '䰪' => ' mèi', + '䰍' => ' cì', + '䰋' => ' mán', + '䯖' => ' láng', + '䯢' => ' mó', + '䯭' => ' xiān', + '䯬' => ' duǒ', + '䯫' => ' hào', + '䯪' => ' kǎo', + '䯨' => ' qiāo', + '䯧' => ' qǐng', + '䯦' => ' mà', + '䯥' => ' àn', + '䯤' => ' kuài', + '䯣' => ' kuì', + '䯡' => ' jiàn', + '䯯' => ' suō', + '䯠' => ' ǎo', + '䯟' => ' duì', + '䯞' => ' kuā', + '䯝' => ' suǐ', + '䯜' => ' tì', + '䯛' => ' wàn', + '䯚' => ' yǎo', + '䯙' => ' pò', + '䯘' => ' huàn', + '䯗' => ' bì', + '䯮' => ' nái', + '䯰' => ' jiè', + '䰊' => ' bó', + '䯾' => ' tiáo', + '䰉' => ' pán', + '䰈' => ' cuó', + '䰇' => ' qí', + '䰆' => ' róu', + '䰄' => ' sāi', + '䰃' => ' péng', + '䰂' => ' cài', + '䰁' => ' fèi', + '䰀' => ' wǒ', + '䯿' => ' zú', + '䯽' => ' póu', + '䯱' => ' pī', + '䯼' => ' dí', + '䯺' => ' kuò', + '䯹' => ' xiān', + '䯸' => ' cì', + '䯷' => ' sōng', + '䯶' => ' mán', + '䯵' => ' niè', + '䯴' => ' cháng', + '䯳' => ' sōng', + '䯲' => ' pā', + '䭥' => ' xuè', + '䭣' => ' cí', + '䱄' => ' jiè', + '䫉' => ' mào', + '䫓' => ' wú', + '䫒' => ' mén', + '䫑' => ' yī', + '䫐' => ' lín', + '䫏' => ' qī', + '䫎' => ' zhuō', + '䫍' => ' fǔ', + '䫌' => ' pǐ', + '䫋' => ' wēi', + '䫊' => ' péi', + '䫈' => ' chěn', + '䫕' => ' dié', + '䫇' => ' rán', + '䫆' => ' chéng', + '䫅' => ' sàn', + '䫄' => ' chuà', + '䫃' => ' chún', + '䫂' => ' duǒ', + '䫁' => ' bì', + '䫀' => ' gěn', + '䪿' => ' shěng', + '䪾' => ' zhěn', + '䫔' => ' qì', + '䫖' => ' chěn', + '䪼' => ' zhuō', + '䫣' => ' xí', + '䫮' => ' chán', + '䫭' => ' huì', + '䫬' => ' zhěn', + '䫫' => ' lóu', + '䫪' => ' shuǎng', + '䫩' => ' sǎn', + '䫨' => ' ào', + '䫦' => ' gé', + '䫥' => ' kuǐ', + '䫤' => ' míng', + '䫢' => ' sī', + '䫗' => ' xiá', + '䫡' => ' yán', + '䫠' => ' pī', + '䫟' => ' hùn', + '䫞' => ' qiāo', + '䫝' => ' fǔ', + '䫜' => ' āo', + '䫛' => ' hóu', + '䫚' => ' guā', + '䫙' => ' sǎng', + '䫘' => ' hé', + '䪽' => ' hào', + '䪻' => ' biàn', + '䫱' => ' ná', + '䪏' => ' nà', + '䪙' => ' pò', + '䪘' => ' wěi', + '䪗' => ' xiá', + '䪖' => ' pò', + '䪕' => ' jú', + '䪔' => ' bǔ', + '䪓' => ' diē', + '䪒' => ' zhù', + '䪑' => ' tuó', + '䪐' => ' bì', + '䪎' => ' suī', + '䪛' => ' fān', + '䪍' => ' lán', + '䪌' => ' zhàn', + '䪋' => ' wèi', + '䪊' => ' lóng', + '䪉' => ' liè', + '䪈' => ' qiàn', + '䪇' => ' bó', + '䪆' => ' tǐ', + '䪅' => ' dú', + '䪄' => ' huáng', + '䪚' => ' dā', + '䪜' => ' chān', + '䪺' => ' gé', + '䪯' => ' yīng', + '䪹' => ' bāi', + '䪸' => ' mín', + '䪷' => ' hòu', + '䪶' => ' jū', + '䪵' => ' yǎ', + '䪴' => ' zhěn', + '䪳' => ' yǔn', + '䪲' => ' kūn', + '䪱' => ' gǎi', + '䪰' => ' yī', + '䪮' => ' chǒu', + '䪝' => ' hù', + '䪭' => ' ruǎn', + '䪬' => ' bó', + '䪫' => ' jīng', + '䪩' => ' yín', + '䪨' => ' báo', + '䪧' => ' chí', + '䪦' => ' hóng', + '䪥' => ' xiè', + '䪤' => ' fán', + '䪞' => ' zá', + '䫰' => ' lìn', + '䫲' => ' hàn', + '䭢' => ' níng', + '䬻' => ' jiàn', + '䭅' => ' hú', + '䭄' => ' shì', + '䭃' => ' rěn', + '䭂' => ' yì', + '䭁' => ' zhì', + '䭀' => ' xùn', + '䬿' => ' wěi', + '䬾' => ' tí', + '䬽' => ' shuì', + '䬼' => ' yuàn', + '䬺' => ' yàng', + '䭇' => ' yē', + '䬹' => ' zhì', + '䬷' => ' shě', + '䬶' => ' èn', + '䬵' => ' gāi', + '䬴' => ' mò', + '䬳' => ' bǎn', + '䬲' => ' gōu', + '䬱' => ' bèn', + '䬰' => ' shào', + '䬯' => ' nián', + '䭆' => ' nè', + '䭈' => ' jiàn', + '䬬' => ' yǐng', + '䭖' => ' zhù', + '䭡' => ' èn', + '䭠' => ' jiǎn', + '䭟' => ' yè', + '䭞' => ' yì', + '䭝' => ' kuài', + '䭛' => ' dàn', + '䭚' => ' chuáng', + '䭙' => ' jǐn', + '䭘' => ' yǐng', + '䭗' => ' yǐng', + '䭕' => ' zǎn', + '䭉' => ' suǐ', + '䭔' => ' duī', + '䭓' => ' èn', + '䭒' => ' xī', + '䭑' => ' lián', + '䭐' => ' yàng', + '䭎' => ' yè', + '䭍' => ' hú', + '䭌' => ' hú', + '䭋' => ' bǎo', + '䭊' => ' yǐng', + '䬮' => ' yí', + '䬫' => ' tí', + '䫳' => ' dú', + '䫿' => ' chāo', + '䬉' => ' huò', + '䬈' => ' duì', + '䬇' => ' yuàn', + '䬆' => ' lì', + '䬅' => ' lì', + '䬄' => ' xù', + '䬃' => ' sà', + '䬂' => ' xuè', + '䬁' => ' yí', + '䬀' => ' yǒu', + '䫾' => ' bī', + '䬋' => ' léng', + '䫽' => ' pāo', + '䫼' => ' xuè', + '䫻' => ' yù', + '䫺' => ' hóng', + '䫹' => ' hóng', + '䫸' => ' chāo', + '䫷' => ' è', + '䫶' => ' fán', + '䫵' => ' mián', + '䫴' => ' jìn', + '䬊' => ' shà', + '䬌' => ' pōu', + '䬪' => ' bó', + '䬛' => ' bì', + '䬨' => ' jiù', + '䬧' => ' yuán', + '䬦' => ' dòu', + '䬥' => ' yì', + '䬤' => ' zàn', + '䬣' => ' xì', + '䬡' => ' zhù', + '䬟' => ' liú', + '䬞' => ' táo', + '䬝' => ' héng', + '䬙' => ' yáo', + '䬍' => ' hū', + '䬘' => ' xiāo', + '䬗' => ' yáng', + '䬖' => ' héng', + '䬕' => ' xiāng', + '䬔' => ' yú', + '䬓' => ' àn', + '䬒' => ' sōu', + '䬑' => ' wèi', + '䬐' => ' ruí', + '䬏' => ' bù', + '䬎' => ' guó', + '䱃' => ' zhì', + '䱅' => ' mò', + '乇' => ' tuō', + '䵬' => ' tà', + '䵶' => ' qú', + '䵵' => ' chuā', + '䵴' => ' yìng', + '䵳' => ' wèi', + '䵲' => ' qiāo', + '䵱' => ' xì', + '䵰' => ' shāng', + '䵯' => ' tuǎn', + '䵮' => ' yàng', + '䵭' => ' zhè', + '䵫' => ' xūn', + '䵹' => ' zhī', + '䵪' => ' gùn', + '䵩' => ' lí', + '䵨' => ' máng', + '䵧' => ' zài', + '䵦' => ' xiè', + '䵥' => ' yù', + '䵤' => ' jiǎn', + '䵣' => ' dá', + '䵢' => ' mèi', + '䵡' => ' jiǎn', + '䵷' => ' wā', + '䵺' => ' tǐng', + '䵟' => ' gǎn', + '䶇' => ' zhòu', + '䶑' => ' tì', + '䶐' => ' wài', + '䶏' => ' tì', + '䶎' => ' hē', + '䶍' => ' dì', + '䶌' => ' pào', + '䶋' => ' xī', + '䶊' => ' nǜ', + '䶉' => ' liú', + '䶈' => ' bó', + '䶆' => ' zhuī', + '䵻' => ' gǔ', + '䶅' => ' hé', + '䶄' => ' píng', + '䶃' => ' hán', + '䶂' => ' zhuó', + '䶁' => ' tà', + '䶀' => ' tà', + '䵿' => ' tiè', + '䵾' => ' fú', + '䵽' => ' cà', + '䵼' => ' shāng', + '䵠' => ' dí', + '䵞' => ' jìng', + '䶓' => ' jì', + '䴶' => ' péng', + '䵁' => ' qiàng', + '䵀' => ' suǒ', + '䴿' => ' méng', + '䴾' => ' cuó', + '䴽' => ' pí', + '䴼' => ' chàn', + '䴻' => ' lí', + '䴺' => ' bù', + '䴸' => ' fū', + '䴷' => ' hún', + '䴵' => ' bǐng', + '䵃' => ' kuàng', + '䴴' => ' tiè', + '䴳' => ' huá', + '䴲' => ' mò', + '䴱' => ' tuō', + '䴰' => ' shú', + '䴯' => ' hū', + '䴮' => ' shàn', + '䴭' => ' cái', + '䴬' => ' yì', + '䴫' => ' líng', + '䵂' => ' zhí', + '䵄' => ' bí', + '䵝' => ' yì', + '䵒' => ' nì', + '䵜' => ' nǒng', + '䵛' => ' qiàn', + '䵚' => ' tǎo', + '䵙' => ' zhā', + '䵘' => ' shài', + '䵗' => ' bó', + '䵖' => ' qiàn', + '䵕' => ' jù', + '䵔' => ' dǒng', + '䵓' => ' lí', + '䵑' => ' nì', + '䵅' => ' áo', + '䵐' => ' chǎn', + '䵏' => ' lǎo', + '䵎' => ' tuān', + '䵌' => ' xiān', + '䵋' => ' wěi', + '䵊' => ' tuān', + '䵉' => ' tóu', + '䵈' => ' kù', + '䵇' => ' xiàn', + '䵆' => ' méng', + '䶒' => ' qí', + '䶔' => ' chí', + '䴩' => ' piáo', + '丢' => ' diū', + '丬' => ' qiáng', + '丫' => ' yā', + '个' => ' gè', + '丩' => ' jiū', + '丨' => ' gǔn', + '丧' => ' sàng', + '並' => ' bìng', + '严' => ' yán', + '两' => ' liǎng', + '丣' => ' yǒu', + '両' => ' liǎng', + '丮' => ' jǐ', + '丠' => ' qiū', + '丟' => ' diū', + '丞' => ' chéng', + '丝' => ' sī', + '东' => ' dōng', + '丛' => ' cóng', + '业' => ' yè', + '丙' => ' bǐng', + '丘' => ' qiū', + '丗' => ' shì', + '中' => ' zhōng', + '丯' => ' jiè', + '丕' => ' pī', + '丼' => ' jǐng', + '乆' => ' jiǔ', + '久' => ' jiǔ', + '乄' => ' wu', + '乃' => ' nǎi', + '乂' => ' yì', + '乁' => ' yí', + '乀' => ' fú', + '丿' => ' piě', + '举' => ' jǔ', + '丽' => ' lì', + '主' => ' zhǔ', + '丰' => ' fēng', + '为' => ' wèi', + '丹' => ' dān', + '丸' => ' wán', + '丷' => ' ha', + '丶' => ' zhǔ', + '丵' => ' zhuó', + '临' => ' lín', + '丳' => ' chǎn', + '串' => ' chuàn', + '丱' => ' guàn', + '世' => ' shì', + '且' => ' qiě', + '䶕' => ' bà', + '䶡' => ' shí', + '䶫' => ' yàn', + '䶪' => ' chà', + '䶩' => ' jì', + '䶨' => ' zhān', + '䶧' => ' yǎo', + '䶦' => ' zé', + '䶥' => ' zhā', + '䶤' => ' huá', + '䶣' => ' ái', + '䶢' => ' jiān', + '䶠' => ' jiǎn', + '䶮' => ' yǎn', + '䶟' => ' xiàn', + '䶞' => ' qí', + '䶝' => ' qià', + '䶜' => ' gǔ', + '䶛' => ' là', + '䶚' => ' qǔ', + '䶙' => ' jù', + '䶘' => ' lì', + '䶗' => ' kè', + '䶖' => ' jìn', + '䶬' => ' jiān', + '䶰' => ' jiāo', + '专' => ' zhuān', + '丈' => ' zhàng', + '丒' => ' chǒu', + '丑' => ' chǒu', + '丐' => ' gài', + '丏' => ' miǎn', + '与' => ' yǔ', + '不' => ' bù', + '丌' => ' jī', + '下' => ' xià', + '上' => ' shàng', + '三' => ' sān', + '万' => ' wàn', + '䶱' => ' tóng', + '丆' => ' hǎn', + '丅' => ' xià', + '丄' => ' shàng', + '七' => ' qī', + '丂' => ' kǎo', + '丁' => ' dīng', + '一' => ' yī', + '䶵' => ' chí', + '䶳' => ' yuè', + '䶲' => ' nán', + '䴪' => ' lù', + '䴧' => ' wēi', + '䱆' => ' shéng', + '䲍' => ' téng', + '䲗' => ' xián', + '䲖' => ' chóu', + '䲕' => ' pū', + '䲔' => ' qíng', + '䲓' => ' yǎn', + '䲒' => ' xiè', + '䲑' => ' yí', + '䲐' => ' lǔ', + '䲏' => ' láo', + '䲎' => ' něi', + '䲌' => ' kuǎn', + '䲙' => ' jié', + '䲋' => ' cén', + '䲊' => ' duò', + '䲉' => ' sī', + '䲆' => ' sū', + '䲅' => ' guī', + '䲄' => ' mín', + '䲃' => ' zǎo', + '䲂' => ' xuán', + '䲁' => ' wèi', + '䲀' => ' zhì', + '䲘' => ' guǎn', + '䲚' => ' lài', + '䱾' => ' lóu', + '䲬' => ' qí', + '䲹' => ' pí', + '䲸' => ' jiè', + '䲵' => ' què', + '䲴' => ' zhèn', + '䲳' => ' háng', + '䲲' => ' gōng', + '䲱' => ' fǎng', + '䲰' => ' yùn', + '䲯' => ' jí', + '䲮' => ' yuán', + '䲪' => ' xì', + '䲛' => ' méng', + '䲨' => ' hóng', + '䲧' => ' dù', + '䲦' => ' dài', + '䲣' => ' yú', + '䲢' => ' téng', + '䲡' => ' qiū', + '䲠' => ' chūn', + '䲟' => ' yìn', + '䲞' => ' lì', + '䲜' => ' yè', + '䱿' => ' chàn', + '䱼' => ' zhǎn', + '䲻' => ' xuán', + '䱒' => ' yè', + '䱜' => ' cuò', + '䱛' => ' huò', + '䱚' => ' lù', + '䱙' => ' shū', + '䱘' => ' lí', + '䱗' => ' cān', + '䱖' => ' liú', + '䱕' => ' móu', + '䱔' => ' tiáo', + '䱓' => ' tíng', + '䱑' => ' xué', + '䱞' => ' liú', + '䱐' => ' fū', + '䱏' => ' tǒu', + '䱎' => ' gèng', + '䱍' => ' gèng', + '䱌' => ' yí', + '䱋' => ' gǒng', + '䱊' => ' mǐ', + '䱉' => ' shàn', + '䱈' => ' qí', + '䱇' => ' shàn', + '䱝' => ' pái', + '䱟' => ' jù', + '䱻' => ' huá', + '䱰' => ' zhòng', + '䱺' => ' hái', + '䱹' => ' zhǎ', + '䱸' => ' sōu', + '䱷' => ' yú', + '䱶' => ' láng', + '䱵' => ' wēng', + '䱴' => ' gèng', + '䱳' => ' zhān', + '䱲' => ' yuán', + '䱱' => ' tí', + '䱯' => ' mú', + '䱠' => ' zhàn', + '䱮' => ' é', + '䱭' => ' gèng', + '䱬' => ' xū', + '䱫' => ' là', + '䱨' => ' là', + '䱥' => ' zhì', + '䱤' => ' xiàn', + '䱣' => ' zú', + '䱢' => ' zhēng', + '䱡' => ' jú', + '䲺' => ' gàn', + '䲼' => ' shēng', + '䴦' => ' yín', + '䴁' => ' yù', + '䴋' => ' huán', + '䴊' => ' yí', + '䴉' => ' huán', + '䴈' => ' ǎo', + '䴇' => ' líng', + '䴆' => ' pú', + '䴅' => ' fén', + '䴄' => ' shùn', + '䴃' => ' náo', + '䴂' => ' xiàng', + '䴀' => ' tóng', + '䴍' => ' yīng', + '䳿' => ' rán', + '䳾' => ' dēng', + '䳽' => ' hè', + '䳻' => ' cán', + '䳺' => ' yàn', + '䳹' => ' kòu', + '䳸' => ' má', + '䳷' => ' cóng', + '䳶' => ' xī', + '䳵' => ' chì', + '䴌' => ' méng', + '䴎' => ' lěi', + '䳳' => ' xù', + '䴛' => ' xiāo', + '䴥' => ' jiā', + '䴤' => ' shēng', + '䴣' => ' hū', + '䴢' => ' mí', + '䴡' => ' lì', + '䴠' => ' yǎo', + '䴟' => ' huán', + '䴞' => ' dí', + '䴝' => ' chuài', + '䴜' => ' wāi', + '䴚' => ' gǎng', + '䴏' => ' yàn', + '䴙' => ' pì', + '䴘' => ' tī', + '䴗' => ' jú', + '䴖' => ' jīng', + '䴕' => ' liè', + '䴔' => ' jiāo', + '䴓' => ' shī', + '䴒' => ' líng', + '䴑' => ' dié', + '䴐' => ' bǎo', + '䳴' => ' tà', + '䳲' => ' zhèn', + '䲽' => ' shí', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/data/words_4 b/lib/vendor/overtrue/pinyin/data/words_4 new file mode 100644 index 0000000000..4a5c91513f --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_4 @@ -0,0 +1,8003 @@ + ' dàn', + '䳔' => ' jú', + '䳓' => ' lǎo', + '䳒' => ' yuán', + '䳑' => ' yǒu', + '䳐' => ' cì', + '䳏' => ' guì', + '䳎' => ' jiù', + '䳍' => ' gōng', + '䳋' => ' tóng', + '䳊' => ' bá', + '䳈' => ' bǎo', + '䳖' => ' niè', + '䳇' => ' wǔ', + '䳆' => ' bái', + '䳅' => ' zhǐ', + '䳄' => ' cí', + '䳃' => ' wǎn', + '䳂' => ' diāo', + '䳁' => ' bó', + '䳀' => ' dié', + '䲿' => ' cí', + '䲾' => ' qiǎo', + '䳕' => ' fú', + '䳗' => ' é', + '䳱' => ' wù', + '䳦' => ' xuān', + '䳰' => ' bǎo', + '䳯' => ' chóng', + '䳮' => ' mò', + '䳭' => ' jí', + '䳬' => ' è', + '䳫' => ' kuí', + '䳪' => ' juàn', + '䳩' => ' yāo', + '䳨' => ' huáng', + '䳧' => ' hóu', + '䳤' => ' biē', + '䳘' => ' é', + '䳣' => ' yuán', + '䳢' => ' qí', + '䳡' => ' yàn', + '䳠' => ' shuì', + '䳟' => ' míng', + '䳞' => ' běng', + '䳝' => ' pǒu', + '䳜' => ' tú', + '䳛' => ' yàn', + '䳚' => ' kàn', + '䳙' => ' xǐng', + '䍗' => ' xuàn', + '䍕' => ' dī', + '冋' => ' jiōng', + '㥎' => ' lái', + '㥜' => ' wèi', + '㥛' => ' jí', + '㥚' => ' yú', + '㥖' => ' cōng', + '㥕' => ' lián', + '㥔' => ' yù', + '㥓' => ' qī', + '㥒' => ' cǎi', + '㥐' => ' yuàn', + '㥏' => ' tiǎn', + '㥍' => ' jì', + '㥞' => ' suì', + '㥌' => ' jú', + '㥋' => ' yī', + '㥊' => ' péng', + '㥉' => ' chè', + '㥈' => ' dié', + '㥇' => ' cán', + '㥆' => ' tuì', + '㥅' => ' shòu', + '㥄' => ' líng', + '㥃' => ' mèn', + '㥝' => ' mǐ', + '㥟' => ' xié', + '㥁' => ' dé', + '㥮' => ' zhòu', + '㥸' => ' mǐn', + '㥷' => ' yè', + '㥶' => ' sè', + '㥵' => ' hùn', + '㥴' => ' yí', + '㥳' => ' yuán', + '㥲' => ' chēn', + '㥱' => ' fěi', + '㥰' => ' sāo', + '㥯' => ' yǐn', + '㥭' => ' tài', + '㥠' => ' xū', + '㥬' => ' páng', + '㥪' => ' lóu', + '㥩' => ' duǒ', + '㥨' => ' shuì', + '㥧' => ' shùn', + '㥦' => ' qiè', + '㥥' => ' yú', + '㥣' => ' huì', + '㥢' => ' qiú', + '㥡' => ' chì', + '㥂' => ' tè', + '㥀' => ' zhí', + '㥺' => ' hé', + '㤔' => ' fù', + '㤠' => ' liè', + '㤟' => ' kǒng', + '㤞' => ' chà', + '㤝' => ' chōng', + '㤜' => ' jué', + '㤛' => ' nín', + '㤚' => ' háng', + '㤘' => ' zhòu', + '㤖' => ' zhù', + '㤕' => ' chù', + '㤓' => ' bèn', + '㤢' => ' yù', + '㤒' => ' gāo', + '㤑' => ' yòu', + '㤐' => ' chān', + '㤏' => ' tóng', + '㤎' => ' gē', + '㤍' => ' qiāo', + '㤌' => ' gān', + '㤋' => ' fēn', + '㤊' => ' xiào', + '㤉' => ' qiā', + '㤡' => ' lì', + '㤤' => ' yú', + '㤿' => ' yān', + '㤲' => ' qiè', + '㤾' => ' sàn', + '㤽' => ' chóu', + '㤺' => ' huǎng', + '㤹' => ' qiú', + '㤸' => ' xì', + '㤷' => ' hān', + '㤶' => ' máng', + '㤵' => ' cí', + '㤴' => ' chè', + '㤳' => ' běi', + '㤱' => ' fù', + '㤥' => ' hài', + '㤰' => ' zuò', + '㤯' => ' jiǒng', + '㤮' => ' guàng', + '㤬' => ' huì', + '㤫' => ' dé', + '㤪' => ' yuàn', + '㤩' => ' kè', + '㤨' => ' gǒng', + '㤧' => ' hóu', + '㤦' => ' lì', + '㥹' => ' fěn', + '㥼' => ' yìn', + '㤇' => ' ǎo', + '㧂' => ' tián', + '㧌' => ' mào', + '㧋' => ' xuǎn', + '㧊' => ' pō', + '㧉' => ' gài', + '㧈' => ' yǐn', + '㧇' => ' mǎo', + '㧆' => ' jīn', + '㧅' => ' mù', + '㧄' => ' qiǎn', + '㧃' => ' shōu', + '㧁' => ' qù', + '㧎' => ' yá', + '㧀' => ' jí', + '㦿' => ' qiǎn', + '㦾' => ' yí', + '㦽' => ' yù', + '㦼' => ' shuàng', + '㦻' => ' xí', + '㦺' => ' rù', + '㦹' => ' yáng', + '㦸' => ' jǐ', + '㦷' => ' yǒng', + '㧍' => ' fǎng', + '㧏' => ' gāng', + '㦵' => ' zhū', + '㧟' => ' kuǎi', + '㧫' => ' ér', + '㧪' => ' guǐ', + '㧩' => ' pèi', + '㧨' => ' qiú', + '㧦' => ' xuàn', + '㧥' => ' xiǎn', + '㧤' => ' chòng', + '㧣' => ' zhū', + '㧢' => ' yīn', + '㧡' => ' hài', + '㧜' => ' liè', + '㧐' => ' sǒng', + '㧚' => ' wǎ', + '㧙' => ' bì', + '㧘' => ' zì', + '㧗' => ' zǐ', + '㧖' => ' è', + '㧕' => ' liǔ', + '㧔' => ' guài', + '㧓' => ' guā', + '㧒' => ' yù', + '㧑' => ' huī', + '㦶' => ' dié', + '㦴' => ' gé', + '㥽' => ' cè', + '㦊' => ' huá', + '㦔' => ' yàn', + '㦓' => ' xiàn', + '㦒' => ' lí', + '㦑' => ' xiàn', + '㦐' => ' nì', + '㦏' => ' sǔn', + '㦎' => ' huò', + '㦍' => ' è', + '㦌' => ' hū', + '㦋' => ' zhā', + '㦉' => ' yì', + '㦖' => ' mèn', + '㦇' => ' lù', + '㦆' => ' hū', + '㦅' => ' diē', + '㦄' => ' má', + '㦃' => ' chǎn', + '㦂' => ' cháng', + '㦁' => ' lián', + '㦀' => ' féng', + '㥿' => ' ào', + '㥾' => ' nì', + '㦕' => ' lóng', + '㦗' => ' jīn', + '㦱' => ' wǒ', + '㦦' => ' xì', + '㦰' => ' jiān', + '㦯' => ' huò', + '㦮' => ' qián', + '㦭' => ' líng', + '㦬' => ' luǒ', + '㦫' => ' zā', + '㦪' => ' xiè', + '㦩' => ' yǐn', + '㦨' => ' lán', + '㦧' => ' cǎn', + '㦥' => ' xuān', + '㦘' => ' jī', + '㦤' => ' yì', + '㦣' => ' wèi', + '㦢' => ' jié', + '㦡' => ' lè', + '㦟' => ' mái', + '㦞' => ' chóu', + '㦝' => ' miǎo', + '㦜' => ' huò', + '㦛' => ' yǔ', + '㦚' => ' biǎn', + '㤈' => ' qìn', + '㤆' => ' fàn', + '㧭' => ' qióng', + '㡖' => ' chuáng', + '㡠' => ' zhèng', + '㡟' => ' zāo', + '㡞' => ' lóu', + '㡝' => ' fèng', + '㡜' => ' xiè', + '㡛' => ' máng', + '㡚' => ' gōu', + '㡙' => ' bī', + '㡘' => ' lián', + '㡗' => ' tí', + '㡕' => ' yīng', + '㡢' => ' màn', + '㡔' => ' wù', + '㡓' => ' kūn', + '㡒' => ' zhūn', + '㡑' => ' qiāo', + '㡏' => ' shù', + '㡌' => ' mào', + '㡋' => ' yé', + '㡊' => ' qià', + '㡉' => ' xián', + '㡈' => ' wèn', + '㡡' => ' chú', + '㡣' => ' lóng', + '㡅' => ' nuǒ', + '㡲' => ' huán', + '㡼' => ' yì', + '㡻' => ' liào', + '㡺' => ' dàn', + '㡹' => ' jū', + '㡸' => ' zhà', + '㡷' => ' běn', + '㡶' => ' zhǐ', + '㡵' => ' líng', + '㡴' => ' lā', + '㡳' => ' zhǐ', + '㡱' => ' jiǔ', + '㡥' => ' yìn', + '㡰' => ' yǔ', + '㡯' => ' zhái', + '㡮' => ' jí', + '㡭' => ' jì', + '㡫' => ' yì', + '㡪' => ' nié', + '㡩' => ' luán', + '㡨' => ' jiān', + '㡧' => ' zhèng', + '㡦' => ' pīn', + '㡇' => ' zhé', + '㡄' => ' xún', + '㡾' => ' xiàn', + '㠖' => ' yǐ', + '㠡' => ' niǎo', + '㠠' => ' lú', + '㠟' => ' lí', + '㠝' => ' cuán', + '㠜' => ' nì', + '㠛' => ' wò', + '㠚' => ' duì', + '㠙' => ' háo', + '㠘' => ' yǔ', + '㠗' => ' ào', + '㠕' => ' wěi', + '㠣' => ' lì', + '㠔' => ' bài', + '㠓' => ' méng', + '㠒' => ' biǎo', + '㠑' => ' zuì', + '㠐' => ' jiào', + '㠏' => ' huá', + '㠎' => ' jí', + '㠍' => ' jí', + '㠌' => ' qī', + '㠋' => ' è', + '㠢' => ' huái', + '㠥' => ' lǜ', + '㡃' => ' huāng', + '㠷' => ' gé', + '㡂' => ' lì', + '㡁' => ' kuǎ', + '㡀' => ' bì', + '㠿' => ' zī', + '㠾' => ' yuān', + '㠽' => ' tóng', + '㠼' => ' sī', + '㠺' => ' shā', + '㠹' => ' jiè', + '㠸' => ' kù', + '㠶' => ' fán', + '㠦' => ' fēng', + '㠵' => ' huāng', + '㠴' => ' rèn', + '㠲' => ' bǐ', + '㠱' => ' jì', + '㠯' => ' yǐ', + '㠮' => ' pēng', + '㠭' => ' zhǎn', + '㠪' => ' jù', + '㠨' => ' yù', + '㠧' => ' mǐ', + '㡽' => ' zhào', + '㡿' => ' chì', + '㤅' => ' ài', + '㣒' => ' cèng', + '㣠' => ' tāo', + '㣟' => ' xì', + '㣞' => ' duó', + '㣝' => ' sōng', + '㣜' => ' xíng', + '㣛' => ' tà', + '㣚' => ' tǒng', + '㣙' => ' dí', + '㣔' => ' dīng', + '㣓' => ' càn', + '㣑' => ' róng', + '㣣' => ' shàn', + '㣐' => ' biàn', + '㣏' => ' jìng', + '㣎' => ' mù', + '㣍' => ' tái', + '㣌' => ' shàn', + '㣈' => ' sì', + '㣇' => ' yì', + '㣆' => ' mí', + '㣅' => ' zàn', + '㣄' => ' qú', + '㣢' => ' tí', + '㣤' => ' jiàn', + '㣂' => ' è', + '㣶' => ' zhān', + '㤄' => ' pèi', + '㤃' => ' fáng', + '㤂' => ' jí', + '㤁' => ' miǎn', + '㣿' => ' zhuó', + '㣾' => ' chà', + '㣽' => ' shù', + '㣼' => ' rěn', + '㣻' => ' yì', + '㣷' => ' nìng', + '㣵' => ' tà', + '㣥' => ' zhì', + '㣲' => ' wéi', + '㣱' => ' zé', + '㣰' => ' xiè', + '㣯' => ' xiè', + '㣭' => ' zōng', + '㣬' => ' qì', + '㣫' => ' zhǒng', + '㣪' => ' huǎn', + '㣧' => ' yìn', + '㣦' => ' wēi', + '㣃' => ' yǔ', + '㣁' => ' bèi', + '㢀' => ' cì', + '㢎' => ' zhé', + '㢚' => ' lǔ', + '㢙' => ' qín', + '㢘' => ' lián', + '㢗' => ' qiào', + '㢖' => ' pān', + '㢔' => ' zǒng', + '㢓' => ' yǎo', + '㢒' => ' chá', + '㢑' => ' tuí', + '㢏' => ' tóu', + '㢍' => ' yǐng', + '㢜' => ' kàng', + '㢋' => ' chǐ', + '㢊' => ' ǎi', + '㢉' => ' chá', + '㢈' => ' tuí', + '㢆' => ' chán', + '㢅' => ' lòng', + '㢄' => ' dòu', + '㢃' => ' láng', + '㢂' => ' yǎn', + '㢁' => ' chǐ', + '㢛' => ' yàn', + '㢝' => ' sū', + '㣀' => ' zhèn', + '㢰' => ' bì', + '㢾' => ' juàn', + '㢽' => ' ěr', + '㢼' => ' biè', + '㢻' => ' ruì', + '㢺' => ' xián', + '㢸' => ' bì', + '㢶' => ' bì', + '㢵' => ' xié', + '㢳' => ' lú', + '㢲' => ' xùn', + '㢯' => ' diāo', + '㢞' => ' yì', + '㢮' => ' chí', + '㢬' => ' hóng', + '㢩' => ' dì', + '㢨' => ' hàn', + '㢧' => ' juàn', + '㢥' => ' dòng', + '㢣' => ' jìng', + '㢡' => ' jiǎng', + '㢠' => ' jiǒng', + '㢟' => ' chān', + '㧬' => ' gǒng', + '㧮' => ' hū', + '㠉' => ' tóng', + '㬮' => ' nàn', + '㬹' => ' zhēng', + '㬸' => ' tiāo', + '㬶' => ' hào', + '㬵' => ' xiáo', + '㬴' => ' hǒng', + '㬳' => ' wǔ', + '㬲' => ' tiān', + '㬱' => ' tì', + '㬰' => ' yú', + '㬯' => ' liè', + '㬭' => ' jiào', + '㬼' => ' fù', + '㬬' => ' jù', + '㬫' => ' yàn', + '㬪' => ' dié', + '㬩' => ' huì', + '㬧' => ' bó', + '㬦' => ' yuè', + '㬥' => ' pù', + '㬤' => ' qī', + '㬣' => ' duì', + '㬡' => ' líng', + '㬻' => ' huāng', + '㬿' => ' tūn', + '㬟' => ' fēn', + '㭓' => ' biàn', + '㭟' => ' gǒng', + '㭞' => ' liè', + '㭝' => ' qiú', + '㭜' => ' róng', + '㭛' => ' pài', + '㭚' => ' lǚ', + '㭙' => ' zhé', + '㭘' => ' gé', + '㭕' => ' qū', + '㭔' => ' lú', + '㭒' => ' sì', + '㭁' => ' réng', + '㭑' => ' mèi', + '㭏' => ' wěi', + '㭎' => ' gāng', + '㭌' => ' móu', + '㭋' => ' bàng', + '㭉' => ' huá', + '㭈' => ' jué', + '㭇' => ' yuàn', + '㭄' => ' xìn', + '㭂' => ' jiǎo', + '㬠' => ' shài', + '㬞' => ' hè', + '㭡' => ' xì', + '㫰' => ' làng', + '㫼' => ' dié', + '㫻' => ' kùn', + '㫹' => ' shù', + '㫸' => ' jiē', + '㫷' => ' jī', + '㫶' => ' zhǒu', + '㫵' => ' fēi', + '㫳' => ' chén', + '㫲' => ' bèi', + '㫱' => ' nǎn', + '㫯' => ' mào', + '㬂' => ' yú', + '㫫' => ' xiǎn', + '㫨' => ' ān', + '㫧' => ' bào', + '㫦' => ' tāo', + '㫥' => ' mǐng', + '㫤' => ' chǎng', + '㫢' => ' qù', + '㫟' => ' yán', + '㫝' => ' dī', + '㫜' => ' tǎn', + '㫽' => ' lù', + '㬃' => ' tái', + '㬝' => ' céng', + '㬐' => ' jìn', + '㬜' => ' jìn', + '㬛' => ' xī', + '㬚' => ' chè', + '㬙' => ' wěi', + '㬘' => ' sù', + '㬗' => ' xiàn', + '㬕' => ' yáng', + '㬔' => ' háo', + '㬓' => ' piào', + '㬒' => ' mǎng', + '㬏' => ' lì', + '㬄' => ' chàn', + '㬎' => ' xiǎn', + '㬍' => ' bó', + '㬌' => ' jìng', + '㬋' => ' hóu', + '㬊' => ' huàn', + '㬉' => ' nuǎn', + '㬈' => ' wēn', + '㬇' => ' huàn', + '㬆' => ' mǐn', + '㬅' => ' màn', + '㭠' => ' xiǎn', + '㭢' => ' xīn', + '㫚' => ' hū', + '㮱' => ' shēn', + '㮿' => ' bì', + '㮾' => ' lǎng', + '㮺' => ' běn', + '㮹' => ' zhǐ', + '㮸' => ' sòng', + '㮷' => ' jī', + '㮶' => ' shuò', + '㮵' => ' zhān', + '㮳' => ' zhèn', + '㮲' => ' chōu', + '㮰' => ' pí', + '㯁' => ' péi', + '㮯' => ' hún', + '㮮' => ' jié', + '㮭' => ' xián', + '㮬' => ' wēng', + '㮫' => ' hé', + '㮪' => ' qióng', + '㮩' => ' xī', + '㮨' => ' jì', + '㮧' => ' wū', + '㮦' => ' suǒ', + '㯀' => ' xuàn', + '㯂' => ' dài', + '㮣' => ' gài', + '㯐' => ' fǎng', + '㯜' => ' cuì', + '㯛' => ' hú', + '㯚' => ' tā', + '㯙' => ' zhé', + '㯘' => ' kuǎn', + '㯗' => ' xián', + '㯖' => ' dé', + '㯕' => ' xī', + '㯔' => ' cuì', + '㯓' => ' tà', + '㯏' => ' gǔ', + '㯄' => ' zhī', + '㯎' => ' nèn', + '㯍' => ' jiǎng', + '㯌' => ' chuán', + '㯋' => ' jiǒng', + '㯊' => ' hén', + '㯉' => ' huò', + '㯈' => ' sù', + '㯇' => ' bì', + '㯆' => ' chǎn', + '㯅' => ' pí', + '㮥' => ' bèn', + '㮢' => ' hóu', + '㭤' => ' niǎo', + '㭴' => ' jiān', + '㮁' => ' xiáo', + '㮀' => ' hán', + '㭿' => ' áng', + '㭾' => ' jué', + '㭽' => ' dǐ', + '㭼' => ' tà', + '㭻' => ' táng', + '㭺' => ' yǎn', + '㭹' => ' xián', + '㭸' => ' tú', + '㭲' => ' jí', + '㮃' => ' wēi', + '㭱' => ' hé', + '㭰' => ' zuī', + '㭯' => ' zhé', + '㭮' => ' zuò', + '㭭' => ' bā', + '㭬' => ' zhuó', + '㭫' => ' cuó', + '㭪' => ' fū', + '㭩' => ' liè', + '㭨' => ' xié', + '㮂' => ' jú', + '㮄' => ' bǎng', + '㮡' => ' guàn', + '㮕' => ' ruǎn', + '㮟' => ' niǎn', + '㮞' => ' jié', + '㮝' => ' hé', + '㮜' => ' zāng', + '㮛' => ' chí', + '㮚' => ' lì', + '㮙' => ' è', + '㮘' => ' máo', + '㮗' => ' qín', + '㮖' => ' jiá', + '㮔' => ' chòng', + '㮅' => ' zhuī', + '㮓' => ' gèn', + '㮒' => ' yān', + '㮑' => ' chā', + '㮐' => ' shěng', + '㮏' => ' nài', + '㮌' => ' mián', + '㮋' => ' yǒu', + '㮈' => ' nài', + '㮇' => ' tiàn', + '㮆' => ' niè', + '㫛' => ' guàng', + '㫙' => ' fú', + '㧯' => ' lǎo', + '㨲' => ' cè', + '㨼' => ' lüè', + '㨻' => ' cán', + '㨺' => ' miǎn', + '㨹' => ' huì', + '㨸' => ' mà', + '㨷' => ' jìn', + '㨶' => ' dǎo', + '㨵' => ' jiǎn', + '㨴' => ' jiàn', + '㨳' => ' guǐ', + '㨱' => ' yáo', + '㨾' => ' yàng', + '㨰' => ' gǔn', + '㨯' => ' huò', + '㨮' => ' dōu', + '㨭' => ' hù', + '㨫' => ' lǎn', + '㨪' => ' huàng', + '㨩' => ' jié', + '㨨' => ' chōu', + '㨧' => ' bèn', + '㨦' => ' sǒng', + '㨽' => ' pì', + '㨿' => ' jù', + '㨤' => ' huì', + '㩎' => ' yè', + '㩛' => ' tuán', + '㩚' => ' méng', + '㩙' => ' sāi', + '㩘' => ' nǐ', + '㩗' => ' xí', + '㩖' => ' qiáng', + '㩔' => ' tún', + '㩓' => ' huǐ', + '㩒' => ' qín', + '㩐' => ' dèn', + '㩍' => ' cè', + '㩀' => ' jù', + '㩌' => ' fèi', + '㩋' => ' xiāo', + '㩊' => ' xuān', + '㩉' => ' dá', + '㩈' => ' yǔn', + '㩇' => ' huò', + '㩆' => ' jiù', + '㩄' => ' shāi', + '㩃' => ' qiān', + '㩁' => ' què', + '㨥' => ' nà', + '㨢' => ' pī', + '㩝' => ' háo', + '㧻' => ' zhuó', + '㨆' => ' lǐn', + '㨅' => ' nèi', + '㨄' => ' zhōu', + '㨃' => ' duǐ', + '㨂' => ' dǒng', + '㨁' => ' zhì', + '㨀' => ' bǐng', + '㧾' => ' hū', + '㧽' => ' gù', + '㧼' => ' biào', + '㧺' => ' tà', + '㨈' => ' jǐ', + '㧹' => ' tè', + '㧸' => ' pēng', + '㧷' => ' tùn', + '㧶' => ' kēng', + '㧵' => ' póu', + '㧴' => ' wǒ', + '㧳' => ' zhuò', + '㧲' => ' sǎn', + '㧱' => ' chèn', + '㧰' => ' lì', + '㨇' => ' pó', + '㨉' => ' mín', + '㨡' => ' hún', + '㨖' => ' zhì', + '㨠' => ' mì', + '㨟' => ' hāi', + '㨞' => ' sù', + '㨝' => ' xiē', + '㨜' => ' qián', + '㨛' => ' shǎn', + '㨚' => ' xún', + '㨙' => ' xié', + '㨘' => ' xǐng', + '㨗' => ' jié', + '㨕' => ' yíng', + '㨊' => ' wěi', + '㨔' => ' hàn', + '㨓' => ' láo', + '㨒' => ' kuī', + '㨑' => ' zōng', + '㨐' => ' bǔ', + '㨏' => ' tān', + '㨎' => ' rú', + '㨍' => ' bāng', + '㨌' => ' gòu', + '㨋' => ' chě', + '㩜' => ' lǎn', + '㩞' => ' cì', + '㫘' => ' mì', + '㪧' => ' xī', + '㪴' => ' jiá', + '㪱' => ' huàn', + '㪯' => ' chá', + '㪮' => ' líng', + '㪭' => ' lú', + '㪬' => ' chuō', + '㪫' => ' ruì', + '㪪' => ' sà', + '㪩' => ' sù', + '㪨' => ' shàn', + '㪦' => ' yìn', + '㪶' => ' hú', + '㪥' => ' zhā', + '㪤' => ' bì', + '㪣' => ' xiāo', + '㪢' => ' shǎo', + '㪡' => ' kài', + '㪠' => ' qiān', + '㪞' => ' mào', + '㪝' => ' liàn', + '㪜' => ' chuǎi', + '㪛' => ' zhěn', + '㪵' => ' bàn', + '㪷' => ' dǒu', + '㪙' => ' kě', + '㫅' => ' chá', + '㫗' => ' hòu', + '㫔' => ' gèn', + '㫓' => ' qǐ', + '㫒' => ' gǒng', + '㫑' => ' zhǐ', + '㫐' => ' yǎo', + '㫏' => ' yǎo', + '㫎' => ' huī', + '㫍' => ' yóu', + '㫊' => ' yǐ', + '㫄' => ' páng', + '㪹' => ' lǒu', + '㫃' => ' yǎn', + '㫂' => ' zhù', + '㫁' => ' duàn', + '㫀' => ' dǐng', + '㪿' => ' zhé', + '㪾' => ' luò', + '㪽' => ' suǒ', + '㪼' => ' kě', + '㪻' => ' juàn', + '㪺' => ' jū', + '㪚' => ' sàn', + '㪘' => ' liǎn', + '㩟' => ' zhài', + '㩯' => ' pó', + '㩹' => ' dié', + '㩸' => ' dié', + '㩷' => ' qiān', + '㩶' => ' niè', + '㩵' => ' è', + '㩴' => ' jú', + '㩳' => ' sǒng', + '㩲' => ' kǔn', + '㩱' => ' jué', + '㩰' => ' jiǎo', + '㩮' => ' qián', + '㩼' => ' zhī', + '㩭' => ' bó', + '㩪' => ' xié', + '㩩' => ' qǐng', + '㩨' => ' huì', + '㩧' => ' bó', + '㩦' => ' xié', + '㩤' => ' fū', + '㩢' => ' miè', + '㩡' => ' luǒ', + '㩠' => ' āo', + '㩻' => ' qī', + '㩽' => ' qí', + '㪗' => ' tǒu', + '㪌' => ' tǒng', + '㪖' => ' lù', + '㪕' => ' diào', + '㪔' => ' sàn', + '㪓' => ' chuái', + '㪒' => ' ní', + '㪑' => ' yè', + '㪐' => ' lù', + '㪏' => ' bǐ', + '㪎' => ' shǎn', + '㪍' => ' bó', + '㪋' => ' hàn', + '㩾' => ' zhuì', + '㪊' => ' qún', + '㪉' => ' hé', + '㪈' => ' guì', + '㪇' => ' xiàn', + '㪆' => ' dǐ', + '㪄' => ' fú', + '㪃' => ' hé', + '㪂' => ' kū', + '㪁' => ' qín', + '㪀' => ' yú', + '㩿' => ' kū', + '㠊' => ' qū', + '㠈' => ' rùn', + '㯞' => ' juàn', + '㕰' => ' xuè', + '㕻' => ' pǒu', + '㕺' => ' xiāo', + '㕹' => ' fá', + '㕸' => ' lì', + '㕷' => ' huà', + '㕶' => ' ň', + '㕵' => ' guó', + '㕴' => ' chén', + '㕲' => ' huá', + '㕱' => ' yóu', + '㕯' => ' nè', + '㖀' => ' lè', + '㕮' => ' fǔ', + '㕭' => ' āo', + '㕬' => ' gōng', + '㕫' => ' fǎng', + '㕪' => ' dǎn', + '㕩' => ' pàng', + '㕨' => ' fàn', + '㕧' => ' xī', + '㕦' => ' huà', + '㕥' => ' shēn', + '㕽' => ' sì', + '㖁' => ' lìn', + '㕣' => ' yǎn', + '㖕' => ' niè', + '㖤' => ' hán', + '㖣' => ' tòu', + '㖢' => ' qí', + '㖡' => ' yè', + '㖠' => ' nuò', + '㖟' => ' shòu', + '㖞' => ' wāi', + '㖘' => ' zhēn', + '㖗' => ' yín', + '㖖' => ' niè', + '㖔' => ' tǔn', + '㖂' => ' yì', + '㖓' => ' hóng', + '㖒' => ' tí', + '㖑' => ' xiè', + '㖐' => ' wěi', + '㖏' => ' niè', + '㖊' => ' xún', + '㖇' => ' ér', + '㖆' => ' qú', + '㖅' => ' xù', + '㖃' => ' hǒu', + '㕤' => ' qiú', + '㕢' => ' gài', + '㖦' => ' dǒng', + '㔵' => ' xuǎn', + '㕁' => ' què', + '㔿' => ' zòu', + '㔾' => ' xiān', + '㔽' => ' yào', + '㔼' => ' sǔn', + '㔺' => ' shì', + '㔹' => ' lè', + '㔸' => ' tī', + '㔷' => ' lòu', + '㔶' => ' gòng', + '㔴' => ' yì', + '㕃' => ' xī', + '㔳' => ' guǐ', + '㔱' => ' yǔ', + '㔰' => ' héng', + '㔯' => ' xuán', + '㔮' => ' nuó', + '㔭' => ' chè', + '㔪' => ' lǔ', + '㔩' => ' è', + '㔨' => ' bèi', + '㔧' => ' lǜ', + '㕂' => ' yín', + '㕄' => ' zhǐ', + '㕡' => ' hé', + '㕒' => ' wēi', + '㕠' => ' shuāng', + '㕟' => ' kuì', + '㕞' => ' shuā', + '㕜' => ' shǐ', + '㕛' => ' xù', + '㕚' => ' zhǎo', + '㕙' => ' jùn', + '㕗' => ' yòu', + '㕖' => ' sù', + '㕕' => ' huàn', + '㕑' => ' chú', + '㕅' => ' jiá', + '㕐' => ' xiě', + '㕏' => ' chú', + '㕎' => ' kè', + '㕌' => ' ài', + '㕋' => ' qín', + '㕊' => ' fū', + '㕉' => ' kè', + '㕈' => ' yǐ', + '㕇' => ' lā', + '㕆' => ' hù', + '㖥' => ' jùn', + '㖧' => ' hūn', + '㔥' => ' bài', + '㗽' => ' xiǎng', + '㘈' => ' yì', + '㘇' => ' róng', + '㘆' => ' tǎi', + '㘅' => ' xián', + '㘄' => ' lēng', + '㘂' => ' cí', + '㘁' => ' yì', + '㘀' => ' zuò', + '㗿' => ' hé', + '㗾' => ' xuē', + '㗼' => ' yè', + '㘊' => ' xī', + '㗻' => ' guō', + '㗷' => ' sǎi', + '㗶' => ' pō', + '㗵' => ' xù', + '㗴' => ' yán', + '㗳' => ' tǎ', + '㗲' => ' huò', + '㗱' => ' jí', + '㗰' => ' cóng', + '㗭' => ' xī', + '㘉' => ' zhì', + '㘋' => ' xián', + '㗫' => ' qiè', + '㘛' => ' kān', + '㘦' => ' qín', + '㘥' => ' yóu', + '㘤' => ' wān', + '㘣' => ' xuán', + '㘢' => ' wěng', + '㘡' => ' xiá', + '㘠' => ' bì', + '㘞' => ' huò', + '㘝' => ' niè', + '㘜' => ' chǐ', + '㘚' => ' hǎn', + '㘌' => ' jù', + '㘙' => ' yán', + '㘗' => ' qū', + '㘖' => ' yán', + '㘕' => ' hǎn', + '㘔' => ' sǎi', + '㘓' => ' lán', + '㘑' => ' lì', + '㘐' => ' pào', + '㘎' => ' hǎn', + '㘍' => ' jí', + '㗬' => ' zhā', + '㗩' => ' xī', + '㖨' => ' lù', + '㖻' => ' niú', + '㗅' => ' hú', + '㗄' => ' kū', + '㗃' => ' wěn', + '㗂' => ' shěng', + '㗁' => ' è', + '㗀' => ' yōu', + '㖿' => ' xié', + '㖾' => ' è', + '㖽' => ' zé', + '㖼' => ' duǒ', + '㖺' => ' chǔn', + '㗇' => ' xiá', + '㖹' => ' pēn', + '㖸' => ' xué', + '㖷' => ' shí', + '㖶' => ' yān', + '㖵' => ' gé', + '㖮' => ' lún', + '㖭' => ' tiǎn', + '㖫' => ' líng', + '㖪' => ' huò', + '㖩' => ' jū', + '㗆' => ' gé', + '㗈' => ' màn', + '㗨' => ' xiē', + '㗘' => ' bó', + '㗧' => ' zhì', + '㗦' => ' láo', + '㗥' => ' kuò', + '㗤' => ' cù', + '㗣' => ' tì', + '㗢' => ' hóng', + '㗜' => ' xiù', + '㗛' => ' xiào', + '㗚' => ' lì', + '㗙' => ' chū', + '㗗' => ' bēi', + '㗉' => ' lüè', + '㗖' => ' dàn', + '㗕' => ' gòu', + '㗔' => ' qiān', + '㗓' => ' zhuī', + '㗒' => ' ài', + '㗑' => ' bai', + '㗏' => ' wāi', + '㗌' => ' zhì', + '㗋' => ' hóu', + '㗊' => ' jí', + '㔦' => ' yǎng', + '㔤' => ' xìn', + '㘨' => ' niè', + '㑯' => ' xǔ', + '㑻' => ' mà', + '㑺' => ' jùn', + '㑹' => ' huì', + '㑸' => ' yáo', + '㑷' => ' tài', + '㑶' => ' xì', + '㑵' => ' hàn', + '㑳' => ' zhòu', + '㑱' => ' rǎo', + '㑰' => ' huì', + '㑮' => ' hún', + '㑽' => ' táng', + '㑪' => ' chái', + '㑩' => ' luó', + '㑨' => ' yǔ', + '㑧' => ' jì', + '㑦' => ' lì', + '㑥' => ' yì', + '㑤' => ' miáo', + '㑣' => ' lán', + '㑟' => ' běng', + '㑞' => ' yìng', + '㑼' => ' lüè', + '㑾' => ' yáo', + '㑜' => ' yì', + '㒌' => ' qióng', + '㒙' => ' mián', + '㒗' => ' tái', + '㒖' => ' ǒu', + '㒕' => ' yāng', + '㒔' => ' shú', + '㒓' => ' tà', + '㒒' => ' pú', + '㒑' => ' kuǐ', + '㒎' => ' sà', + '㒍' => ' léi', + '㒊' => ' sè', + '㑿' => ' zhào', + '㒉' => ' tǎng', + '㒈' => ' hàn', + '㒇' => ' wǔ', + '㒆' => ' chì', + '㒅' => ' qǐ', + '㒄' => ' rǎn', + '㒃' => ' èr', + '㒂' => ' zhuó', + '㒁' => ' yǔ', + '㒀' => ' zhāi', + '㑝' => ' lòng', + '㑛' => ' sù', + '㒛' => ' diào', + '㐫' => ' xiōng', + '㐵' => ' rú', + '㐴' => ' pān', + '㐳' => ' wù', + '㐲' => ' dài', + '㐱' => ' zhěn', + '㐰' => ' xìn', + '㐯' => ' yōng', + '㐮' => ' xiāng', + '㐭' => ' lǐn', + '㐬' => ' liú', + '㐩' => ' xíng', + '㐸' => ' qiàn', + '㐨' => ' xù', + '㐤' => ' dān', + '㐡' => ' nuò', + '㐜' => ' chóu', + '㐖' => ' xié', + '㐌' => ' yí', + '㐆' => ' yǐn', + '㐅' => ' wǔ', + '㐄' => ' kuà', + '㐁' => ' tiàn', + '㐷' => ' mǎ', + '㐹' => ' yì', + '㑚' => ' nuó', + '㑊' => ' yì', + '㑙' => ' dié', + '㑘' => ' jiè', + '㑗' => ' shēn', + '㑔' => ' xǔ', + '㑐' => ' shū', + '㑏' => ' zhù', + '㑎' => ' nǎo', + '㑍' => ' lèi', + '㑌' => ' kuāng', + '㑋' => ' qióng', + '㑉' => ' sù', + '㐺' => ' yín', + '㑈' => ' dòng', + '㑇' => ' zhòu', + '㑅' => ' zuò', + '㑄' => ' wǔ', + '㑃' => ' ǎo', + '㑂' => ' fǎng', + '㑁' => ' zhuō', + '㐽' => ' fēng', + '㐼' => ' chèng', + '㐻' => ' nèi', + '㒚' => ' yìn', + '㒜' => ' yǔ', + '㔣' => ' léi', + '㓵' => ' è', + '㔁' => ' dēng', + '㔀' => ' lüè', + '㓾' => ' xī', + '㓽' => ' chóng', + '㓼' => ' chì', + '㓺' => ' jiān', + '㓹' => ' ruì', + '㓸' => ' zhuō', + '㓷' => ' yì', + '㓶' => ' qiè', + '㓴' => ' ruǎn', + '㔃' => ' jué', + '㓳' => ' dī', + '㓲' => ' piān', + '㓱' => ' tóu', + '㓰' => ' huà', + '㓯' => ' lí', + '㓭' => ' shé', + '㓪' => ' lǎng', + '㓩' => ' xuān', + '㓨' => ' cí', + '㓧' => ' gān', + '㔂' => ' lín', + '㔄' => ' sù', + '㓥' => ' tāng', + '㔕' => ' jí', + '㔢' => ' jué', + '㔡' => ' biē', + '㔠' => ' xiā', + '㔞' => ' kuài', + '㔝' => ' liǎng', + '㔜' => ' bá', + '㔚' => ' jié', + '㔙' => ' bēng', + '㔘' => ' chù', + '㔗' => ' fèi', + '㔓' => ' jiǎn', + '㔅' => ' xiào', + '㔒' => ' xí', + '㔑' => ' chì', + '㔏' => ' lì', + '㔎' => ' xiè', + '㔍' => ' chuā', + '㔌' => ' zòu', + '㔋' => ' jiān', + '㔊' => ' zhǎn', + '㔉' => ' zhǔ', + '㔆' => ' zàn', + '㓦' => ' bāi', + '㓤' => ' qià', + '㒝' => ' miè', + '㒲' => ' cái', + '㒿' => ' lí', + '㒾' => ' shì', + '㒽' => ' quān', + '㒼' => ' mán', + '㒻' => ' mào', + '㒸' => ' suì', + '㒷' => ' guǎ', + '㒵' => ' mào', + '㒴' => ' gǔ', + '㒳' => ' liǎng', + '㒰' => ' quán', + '㓂' => ' kòu', + '㒫' => ' jì', + '㒩' => ' luǒ', + '㒧' => ' lì', + '㒦' => ' lěi', + '㒥' => ' fēng', + '㒤' => ' chè', + '㒡' => ' yóu', + '㒠' => ' xiè', + '㒟' => ' niǎo', + '㒞' => ' jùn', + '㓁' => ' wǎng', + '㓃' => ' dù', + '㓣' => ' qià', + '㓖' => ' bì', + '㓢' => ' luò', + '㓡' => ' fǔ', + '㓠' => ' diàn', + '㓟' => ' pí', + '㓞' => ' qià', + '㓝' => ' xíng', + '㓜' => ' yòu', + '㓚' => ' gōng', + '㓘' => ' sù', + '㓗' => ' jié', + '㓔' => ' xiè', + '㓄' => ' zhèn', + '㓓' => ' nán', + '㓑' => ' xìng', + '㓐' => ' lù', + '㓏' => ' jiǒng', + '㓎' => ' qīn', + '㓌' => ' chēng', + '㓋' => ' gòng', + '㓊' => ' dòng', + '㓉' => ' huò', + '㓈' => ' bìng', + '㓅' => ' tīng', + '㘧' => ' xù', + '㘩' => ' bì', + '㠇' => ' jiù', + '㝧' => ' wěn', + '㝴' => ' wán', + '㝲' => ' qǐn', + '㝱' => ' mèng', + '㝰' => ' mián', + '㝯' => ' qiáo', + '㝮' => ' cuì', + '㝭' => ' xǐng', + '㝫' => ' lóng', + '㝪' => ' diàn', + '㝩' => ' kāng', + '㝦' => ' jùn', + '㝶' => ' ài', + '㝥' => ' mǐ', + '㝤' => ' gòu', + '㝣' => ' yì', + '㝢' => ' yǔ', + '㝡' => ' zuì', + '㝠' => ' míng', + '㝟' => ' máo', + '㝞' => ' yā', + '㝝' => ' lín', + '㝛' => ' sù', + '㝵' => ' dé', + '㝸' => ' biàn', + '㝙' => ' yín', + '㞅' => ' luò', + '㞐' => ' jū', + '㞏' => ' zhé', + '㞎' => ' bǎ', + '㞌' => ' yùn', + '㞋' => ' niǎn', + '㞊' => ' xù', + '㞉' => ' zā', + '㞈' => ' bō', + '㞇' => ' wěi', + '㞆' => ' jǐ', + '㞄' => ' ān', + '㝹' => ' nóu', + '㞃' => ' jì', + '㞂' => ' tuǐ', + '㞁' => ' yào', + '㞀' => ' huī', + '㝿' => ' bǒ', + '㝾' => ' zuǒ', + '㝽' => ' chuí', + '㝼' => ' yū', + '㝻' => ' jǐn', + '㝺' => ' lián', + '㝚' => ' yán', + '㝘' => ' yóng', + '㞒' => ' xiè', + '㜰' => ' yuè', + '㜺' => ' zàn', + '㜹' => ' qú', + '㜸' => ' niè', + '㜷' => ' mí', + '㜶' => ' wǎn', + '㜵' => ' niǎo', + '㜴' => ' mèng', + '㜳' => ' huái', + '㜲' => ' wěng', + '㜱' => ' zhì', + '㜯' => ' xī', + '㜼' => ' zhí', + '㜮' => ' làn', + '㜫' => ' mà', + '㜪' => ' shēn', + '㜩' => ' ào', + '㜨' => ' nái', + '㜧' => ' yuè', + '㜦' => ' xín', + '㜥' => ' mái', + '㜤' => ' niǎn', + '㜣' => ' rán', + '㜻' => ' liàn', + '㜽' => ' zǐ', + '㝗' => ' láng', + '㝋' => ' liǎo', + '㝖' => ' yí', + '㝕' => ' níng', + '㝔' => ' yǎo', + '㝓' => ' kè', + '㝑' => ' máng', + '㝐' => ' róng', + '㝏' => ' jiè', + '㝎' => ' dìng', + '㝍' => ' xiě', + '㝌' => ' jiù', + '㝊' => ' shǒu', + '㜾' => ' hái', + '㝉' => ' zhù', + '㝈' => ' luán', + '㝇' => ' chún', + '㝅' => ' gòu', + '㝄' => ' chún', + '㝃' => ' miǎn', + '㝂' => ' zhì', + '㝁' => ' xuān', + '㝀' => ' hào', + '㜿' => ' xù', + '㞑' => ' wěi', + '㞓' => ' qì', + '㜠' => ' cuī', + '㟛' => ' zàn', + '㟨' => ' duān', + '㟧' => ' è', + '㟦' => ' yùn', + '㟤' => ' lù', + '㟢' => ' qí', + '㟠' => ' gǎng', + '㟟' => ' xiàng', + '㟞' => ' zhàn', + '㟝' => ' péi', + '㟜' => ' mí', + '㟚' => ' qí', + '㟪' => ' wēi', + '㟙' => ' zé', + '㟘' => ' tiáo', + '㟖' => ' lòng', + '㟔' => ' hán', + '㟓' => ' qí', + '㟒' => ' qūn', + '㟑' => ' bó', + '㟐' => ' mǎng', + '㟏' => ' hán', + '㟎' => ' tuǒ', + '㟩' => ' mín', + '㟫' => ' quán', + '㟌' => ' máng', + '㟺' => ' lóu', + '㠆' => ' dān', + '㠅' => ' fú', + '㠄' => ' xí', + '㠂' => ' áo', + '㠀' => ' dǎo', + '㟿' => ' mǎng', + '㟾' => ' yōng', + '㟽' => ' biǎo', + '㟼' => ' áo', + '㟻' => ' qiàn', + '㟹' => ' láo', + '㟬' => ' sǒu', + '㟷' => ' da', + '㟶' => ' yuán', + '㟵' => ' gǎng', + '㟴' => ' kuài', + '㟳' => ' lì', + '㟲' => ' jué', + '㟱' => ' yǎo', + '㟰' => ' mǐng', + '㟮' => ' tū', + '㟭' => ' mín', + '㟍' => ' láng', + '㟋' => ' duì', + '㞔' => ' yí', + '㞡' => ' zhǎn', + '㞭' => ' dài', + '㞬' => ' qìn', + '㞫' => ' jù', + '㞪' => ' náo', + '㞩' => ' lán', + '㞨' => ' zǐ', + '㞧' => ' huì', + '㞦' => ' jǐ', + '㞥' => ' cén', + '㞤' => ' yín', + '㞠' => ' láo', + '㞰' => ' xǔ', + '㞟' => ' diàn', + '㞞' => ' sóng', + '㞜' => ' tuī', + '㞛' => ' jǐ', + '㞚' => ' qì', + '㞙' => ' niào', + '㞘' => ' dū', + '㞗' => ' qiú', + '㞖' => ' cí', + '㞕' => ' xiè', + '㞯' => ' jié', + '㞱' => ' cōng', + '㟊' => ' fú', + '㞿' => ' chì', + '㟉' => ' láo', + '㟈' => ' qiú', + '㟇' => ' cuò', + '㟆' => ' huá', + '㟅' => ' yáng', + '㟄' => ' xiáng', + '㟃' => ' sī', + '㟂' => ' mǔ', + '㟁' => ' àn', + '㟀' => ' lián', + '㞾' => ' ní', + '㞲' => ' yòng', + '㞽' => ' xuè', + '㞼' => ' chéng', + '㞻' => ' hào', + '㞺' => ' zú', + '㞹' => ' kě', + '㞸' => ' suì', + '㞷' => ' huáng', + '㞶' => ' mǐn', + '㞴' => ' chí', + '㞳' => ' dǒu', + '㜡' => ' cōng', + '㜞' => ' qiàn', + '㘪' => ' hào', + '㙷' => ' zhí', + '㚃' => ' yūn', + '㚂' => ' nàng', + '㚁' => ' qiào', + '㚀' => ' xī', + '㙾' => ' xì', + '㙼' => ' lěi', + '㙻' => ' chán', + '㙺' => ' kuí', + '㙹' => ' méng', + '㙸' => ' bào', + '㙶' => ' táng', + '㚆' => ' fù', + '㙵' => ' tái', + '㙴' => ' chàn', + '㙳' => ' kǎn', + '㙲' => ' yǒng', + '㙱' => ' hào', + '㙰' => ' xiè', + '㙯' => ' yì', + '㙮' => ' dā', + '㙬' => ' yín', + '㙫' => ' jí', + '㚅' => ' lóng', + '㚇' => ' zōng', + '㙩' => ' liáo', + '㚗' => ' qié', + '㚡' => ' jǐ', + '㚠' => ' xiāo', + '㚟' => ' chuò', + '㚞' => ' shěn', + '㚝' => ' zhuī', + '㚜' => ' yù', + '㚛' => ' xì', + '㚚' => ' kōng', + '㚙' => ' jiā', + '㚘' => ' bàn', + '㚖' => ' gǎo', + '㚉' => ' gǔ', + '㚕' => ' fú', + '㚔' => ' niè', + '㚓' => ' lǎi', + '㚒' => ' shǎn', + '㚐' => ' tào', + '㚏' => ' gǎo', + '㚍' => ' kuǐ', + '㚌' => ' huà', + '㚋' => ' diāo', + '㚊' => ' kāi', + '㙪' => ' yì', + '㙨' => ' jì', + '㚣' => ' xiáo', + '㘹' => ' cí', + '㙈' => ' xià', + '㙇' => ' chù', + '㙅' => ' bǎo', + '㙄' => ' bì', + '㙃' => ' bāng', + '㙂' => ' duì', + '㙁' => ' méi', + '㙀' => ' liù', + '㘿' => ' niè', + '㘺' => ' fá', + '㘸' => ' zàng', + '㙊' => ' cháng', + '㘷' => ' ài', + '㘶' => ' jié', + '㘵' => ' bù', + '㘴' => ' zuò', + '㘲' => ' jú', + '㘱' => ' tān', + '㘰' => ' zhēn', + '㘭' => ' ào', + '㘬' => ' ào', + '㘫' => ' jǐng', + '㙉' => ' tiǎn', + '㙍' => ' duō', + '㙦' => ' xié', + '㙛' => ' bǔ', + '㙥' => ' gùn', + '㙤' => ' xià', + '㙣' => ' zhàng', + '㙢' => ' mán', + '㙡' => ' zōng', + '㙠' => ' yī', + '㙟' => ' lǎng', + '㙞' => ' niè', + '㙝' => ' xié', + '㙜' => ' chí', + '㙚' => ' xīng', + '㙎' => ' wēi', + '㙙' => ' lǒng', + '㙘' => ' yāo', + '㙗' => ' wēi', + '㙕' => ' kuài', + '㙔' => ' wěi', + '㙓' => ' kuí', + '㙒' => ' yě', + '㙑' => ' yǔ', + '㙐' => ' duǒ', + '㙏' => ' fù', + '㚢' => ' nú', + '㚤' => ' yì', + '㜝' => ' ǎn', + '㛴' => ' nǎo', + '㛿' => ' zhì', + '㛾' => ' xián', + '㛼' => ' chā', + '㛻' => ' kuā', + '㛺' => ' ān', + '㛹' => ' pián', + '㛸' => ' shù', + '㛷' => ' jī', + '㛶' => ' tàn', + '㛵' => ' chēng', + '㛳' => ' yì', + '㜃' => ' liàn', + '㛲' => ' fà', + '㛱' => ' wěi', + '㛯' => ' fàn', + '㛮' => ' sǎo', + '㛭' => ' xī', + '㛬' => ' lù', + '㛫' => ' xī', + '㛪' => ' yàn', + '㛩' => ' zhóu', + '㛨' => ' qiǎng', + '㜂' => ' fēng', + '㜄' => ' xún', + '㛦' => ' lǎn', + '㜑' => ' fú', + '㜜' => ' ào', + '㜛' => ' nèn', + '㜚' => ' sù', + '㜙' => ' lù', + '㜘' => ' jù', + '㜗' => ' cān', + '㜖' => ' cáo', + '㜕' => ' lián', + '㜓' => ' dá', + '㜒' => ' yì', + '㜐' => ' shù', + '㜅' => ' xù', + '㜏' => ' yún', + '㜎' => ' xī', + '㜍' => ' táng', + '㜌' => ' nǒu', + '㜋' => ' yì', + '㜊' => ' zhǎn', + '㜉' => ' yōng', + '㜈' => ' mù', + '㜇' => ' huì', + '㜆' => ' mì', + '㛧' => ' mǎn', + '㛥' => ' tà', + '㚥' => ' yú', + '㚲' => ' chān', + '㚿' => ' páo', + '㚾' => ' xiōng', + '㚽' => ' qiǎo', + '㚻' => ' jī', + '㚺' => ' yùn', + '㚹' => ' mǎo', + '㚷' => ' ěr', + '㚶' => ' sì', + '㚵' => ' dōng', + '㚴' => ' bù', + '㚱' => ' qiū', + '㛁' => ' pēng', + '㚰' => ' pēi', + '㚯' => ' xín', + '㚭' => ' yóu', + '㚬' => ' jūn', + '㚫' => ' sà', + '㚪' => ' hào', + '㚩' => ' rǎn', + '㚨' => ' shěn', + '㚧' => ' yǎn', + '㚦' => ' yí', + '㛀' => ' chú', + '㛂' => ' nuǒ', + '㛤' => ' lí', + '㛕' => ' yì', + '㛣' => ' yún', + '㛞' => ' lòng', + '㛝' => ' bèi', + '㛜' => ' yóu', + '㛛' => ' xìn', + '㛚' => ' tǒng', + '㛙' => ' xīn', + '㛘' => ' pò', + '㛗' => ' qiē', + '㛖' => ' suō', + '㛔' => ' fēng', + '㛃' => ' jié', + '㛓' => ' xī', + '㛒' => ' dòu', + '㛑' => ' càn', + '㛐' => ' sǒu', + '㛏' => ' qiú', + '㛎' => ' lǚ', + '㛍' => ' qiè', + '㛊' => ' duǒ', + '㛆' => ' duò', + '㛅' => ' èr', + '㛄' => ' yī', + '㯝' => ' lù', + '㯟' => ' lù', + '䍔' => ' gōng', + '䃬' => ' wěi', + '䃶' => ' huái', + '䃵' => ' niǎo', + '䃴' => ' zhū', + '䃳' => ' là', + '䃲' => ' pán', + '䃱' => ' xiàn', + '䃰' => ' cā', + '䃯' => ' lì', + '䃮' => ' dá', + '䃭' => ' gǎn', + '䃫' => ' dǎn', + '䃸' => ' xiàn', + '䃪' => ' tán', + '䃩' => ' náo', + '䃧' => ' lóng', + '䃦' => ' dūn', + '䃥' => ' chuáng', + '䃤' => ' sù', + '䃣' => ' huǐ', + '䃢' => ' qīn', + '䃡' => ' jīn', + '䃠' => ' xuàn', + '䃷' => ' yíng', + '䃹' => ' làn', + '䃝' => ' qiào', + '䄈' => ' dòu', + '䄓' => ' huáng', + '䄒' => ' niè', + '䄑' => ' huó', + '䄐' => ' quàn', + '䄏' => ' yú', + '䄎' => ' qǐ', + '䄍' => ' zhà', + '䄌' => ' zhuì', + '䄋' => ' yǎn', + '䄉' => ' é', + '䄇' => ' chéng', + '䃺' => ' mó', + '䄆' => ' huó', + '䄅' => ' juàn', + '䄄' => ' yīn', + '䄂' => ' liù', + '䄁' => ' yì', + '䄀' => ' huò', + '䃿' => ' fū', + '䃾' => ' bǐ', + '䃽' => ' guǐ', + '䃻' => ' bà', + '䃞' => ' shú', + '䃜' => ' yī', + '䄕' => ' shè', + '䂲' => ' fǎ', + '䂼' => ' niè', + '䂻' => ' zhèng', + '䂺' => ' wǒ', + '䂹' => ' suǒ', + '䂸' => ' guó', + '䂷' => ' guāi', + '䂶' => ' jié', + '䂵' => ' gōng', + '䂴' => ' yán', + '䂳' => ' cuǒ', + '䂱' => ' ruì', + '䂾' => ' lǎi', + '䂰' => ' là', + '䂯' => ' guài', + '䂮' => ' lüè', + '䂭' => ' qiāo', + '䂬' => ' gǒng', + '䂫' => ' hāng', + '䂪' => ' qiǎo', + '䂩' => ' yàn', + '䂧' => ' zhěn', + '䂦' => ' zhēn', + '䂽' => ' diào', + '䂿' => ' tà', + '䃛' => ' lián', + '䃏' => ' xīng', + '䃚' => ' cù', + '䃙' => ' lù', + '䃘' => ' kēng', + '䃗' => ' bō', + '䃖' => ' wù', + '䃕' => ' láo', + '䃔' => ' hóng', + '䃓' => ' gòu', + '䃒' => ' hé', + '䃑' => ' bān', + '䃎' => ' zhà', + '䃀' => ' cuì', + '䃍' => ' zhào', + '䃌' => ' zhēn', + '䃋' => ' yú', + '䃊' => ' jǔ', + '䃉' => ' mín', + '䃈' => ' jiē', + '䃇' => ' mián', + '䃅' => ' dī', + '䃂' => ' gǔn', + '䃁' => ' yā', + '䄔' => ' jǔ', + '䄘' => ' péng', + '䂤' => ' fù', + '䅝' => ' kōng', + '䅧' => ' yān', + '䅦' => ' máo', + '䅥' => ' jié', + '䅤' => ' qì', + '䅣' => ' huáng', + '䅢' => ' jiù', + '䅡' => ' xǔ', + '䅠' => ' tí', + '䅟' => ' cǎn', + '䅞' => ' nè', + '䅜' => ' duò', + '䅪' => ' tuí', + '䅛' => ' chāng', + '䅚' => ' quǎn', + '䅙' => ' hùn', + '䅘' => ' lái', + '䅗' => ' suì', + '䅖' => ' ān', + '䅕' => ' jū', + '䅔' => ' zī', + '䅓' => ' jǔ', + '䅒' => ' máng', + '䅩' => ' zhǐ', + '䅬' => ' ài', + '䅐' => ' jiǎn', + '䅹' => ' lǒu', + '䆃' => ' dào', + '䆂' => ' lián', + '䆁' => ' gāo', + '䆀' => ' měi', + '䅿' => ' huáng', + '䅾' => ' cén', + '䅽' => ' xīn', + '䅼' => ' mán', + '䅻' => ' lí', + '䅺' => ' biāo', + '䅸' => ' shēn', + '䅭' => ' páng', + '䅷' => ' tú', + '䅶' => ' nòu', + '䅵' => ' zhuó', + '䅴' => ' suǒ', + '䅳' => ' chú', + '䅲' => ' qí', + '䅱' => ' hùn', + '䅰' => ' ěn', + '䅯' => ' táng', + '䅮' => ' càng', + '䅑' => ' ruí', + '䅏' => ' huì', + '䄙' => ' míng', + '䄧' => ' réng', + '䄱' => ' fāng', + '䄰' => ' yá', + '䄯' => ' jiǎn', + '䄮' => ' fū', + '䄭' => ' nián', + '䄬' => ' yí', + '䄫' => ' qǐ', + '䄪' => ' diǎo', + '䄩' => ' yì', + '䄨' => ' yú', + '䄦' => ' liǎo', + '䄳' => ' xiān', + '䄥' => ' líng', + '䄤' => ' lài', + '䄢' => ' qí', + '䄡' => ' dān', + '䄠' => ' shàn', + '䄟' => ' cuī', + '䄝' => ' chuāng', + '䄜' => ' lí', + '䄛' => ' lóu', + '䄚' => ' cáo', + '䄲' => ' ruì', + '䄶' => ' bì', + '䅎' => ' yǒu', + '䅃' => ' qióng', + '䅍' => ' tǐng', + '䅌' => ' juān', + '䅋' => ' wǎn', + '䅊' => ' chá', + '䅉' => ' yà', + '䅈' => ' yuàn', + '䅇' => ' sù', + '䅆' => ' zì', + '䅅' => ' guī', + '䅄' => ' lì', + '䅂' => ' hé', + '䄷' => ' shí', + '䅁' => ' àn', + '䅀' => ' liè', + '䄿' => ' yì', + '䄾' => ' rù', + '䄽' => ' tiǎn', + '䄼' => ' tiǎn', + '䄻' => ' táo', + '䄺' => ' zhì', + '䄹' => ' nián', + '䄸' => ' pò', + '䂥' => ' mín', + '䂣' => ' cí', + '䆅' => ' zī', + '䀏' => ' xuàn', + '䀙' => ' qì', + '䀘' => ' xié', + '䀗' => ' jué', + '䀖' => ' tiān', + '䀕' => ' zhèn', + '䀔' => ' rèn', + '䀓' => ' huàn', + '䀒' => ' qiān', + '䀑' => ' wò', + '䀐' => ' shān', + '䀎' => ' miǎn', + '䀛' => ' mèi', + '䀍' => ' kàn', + '䀌' => ' xì', + '䀋' => ' yán', + '䀊' => ' jiǎo', + '䀉' => ' qiáo', + '䀈' => ' jì', + '䀇' => ' gǔ', + '䀆' => ' jìn', + '䀅' => ' shè', + '䀄' => ' méng', + '䀚' => ' áng', + '䀜' => ' gǔ', + '䀂' => ' ān', + '䀪' => ' háng', + '䀴' => ' yǐng', + '䀳' => ' ài', + '䀲' => ' mù', + '䀱' => ' fēng', + '䀰' => ' gǔ', + '䀯' => ' bǔ', + '䀮' => ' huāng', + '䀭' => ' gāi', + '䀬' => ' quán', + '䀫' => ' jiá', + '䀩' => ' luò', + '䀞' => ' tāo', + '䀨' => ' huà', + '䀧' => ' hǒng', + '䀦' => ' gǔ', + '䀥' => ' shuò', + '䀤' => ' mào', + '䀣' => ' bì', + '䀢' => ' shùn', + '䀡' => ' chàn', + '䀠' => ' jù', + '䀟' => ' fán', + '䀃' => ' tuí', + '䀁' => ' yòu', + '䀶' => ' liàng', + '㿘' => ' yíng', + '㿤' => ' chǔn', + '㿣' => ' hē', + '㿢' => ' yào', + '㿠' => ' huàng', + '㿟' => ' bái', + '㿞' => ' mào', + '㿜' => ' biě', + '㿛' => ' lì', + '㿚' => ' luò', + '㿙' => ' pì', + '㿗' => ' tuí', + '㿦' => ' nìng', + '㿖' => ' lú', + '㿕' => ' yán', + '㿔' => ' lěi', + '㿓' => ' jiá', + '㿒' => ' dǎo', + '㿑' => ' yào', + '㿏' => ' qún', + '㿎' => ' fèn', + '㿍' => ' jiè', + '㿌' => ' xiān', + '㿥' => ' hé', + '㿧' => ' chóu', + '䀀' => ' fàn', + '㿵' => ' rǎn', + '㿿' => ' yǎ', + '㿾' => ' zhù', + '㿽' => ' xī', + '㿼' => ' yán', + '㿻' => ' gān', + '㿺' => ' báo', + '㿹' => ' tà', + '㿸' => ' wǎn', + '㿷' => ' cuó', + '㿶' => ' bāng', + '㿴' => ' dā', + '㿨' => ' lì', + '㿳' => ' zī', + '㿱' => ' xué', + '㿰' => ' áo', + '㿯' => ' dá', + '㿮' => ' yàng', + '㿭' => ' chè', + '㿬' => ' bā', + '㿫' => ' bì', + '㿪' => ' huán', + '㿩' => ' tǎng', + '䀵' => ' shùn', + '䀷' => ' jié', + '䂢' => ' dǒng', + '䁺' => ' shì', + '䂄' => ' huò', + '䂃' => ' jiào', + '䂂' => ' qú', + '䂁' => ' chán', + '䂀' => ' xī', + '䁿' => ' mò', + '䁾' => ' miè', + '䁽' => ' liè', + '䁼' => ' mò', + '䁻' => ' shuò', + '䁹' => ' bì', + '䂆' => ' xù', + '䁸' => ' náng', + '䁷' => ' jué', + '䁶' => ' jī', + '䁵' => ' biǎn', + '䁴' => ' zhǎn', + '䁳' => ' mǎng', + '䁲' => ' mái', + '䁱' => ' kōu', + '䁰' => ' jiǎng', + '䁯' => ' xī', + '䂅' => ' xiān', + '䂇' => ' niǔ', + '䁭' => ' biāo', + '䂖' => ' shí', + '䂡' => ' dǐ', + '䂠' => ' shǐ', + '䂟' => ' jiā', + '䂞' => ' zhè', + '䂝' => ' jié', + '䂜' => ' bàng', + '䂛' => ' yú', + '䂚' => ' yáo', + '䂙' => ' duī', + '䂗' => ' kū', + '䂕' => ' huì', + '䂈' => ' tóng', + '䂔' => ' xìng', + '䂒' => ' qià', + '䂑' => ' jī', + '䂐' => ' zhuō', + '䂏' => ' diāo', + '䂎' => ' zuǎn', + '䂍' => ' bó', + '䂌' => ' chōng', + '䂊' => ' yù', + '䂉' => ' hóu', + '䁮' => ' qián', + '䁬' => ' céng', + '䀸' => ' chì', + '䁅' => ' měng', + '䁏' => ' yǎo', + '䁎' => ' chéng', + '䁍' => ' qià', + '䁌' => ' yù', + '䁋' => ' xiè', + '䁊' => ' wò', + '䁉' => ' qì', + '䁈' => ' qì', + '䁇' => ' mì', + '䁆' => ' yè', + '䁄' => ' xìng', + '䁑' => ' yáng', + '䁃' => ' biāo', + '䁂' => ' xiàn', + '䁁' => ' liàng', + '䀿' => ' dì', + '䀾' => ' dǔ', + '䀽' => ' yán', + '䀼' => ' chēn', + '䀻' => ' pìng', + '䀺' => ' chōu', + '䀹' => ' jié', + '䁐' => ' yīng', + '䁒' => ' jí', + '䁫' => ' hú', + '䁟' => ' chá', + '䁪' => ' zhǎn', + '䁩' => ' yú', + '䁨' => ' huò', + '䁧' => ' miáo', + '䁦' => ' qù', + '䁥' => ' nì', + '䁤' => ' chè', + '䁣' => ' chuán', + '䁢' => ' xuán', + '䁠' => ' lián', + '䁞' => ' shěng', + '䁓' => ' zōng', + '䁝' => ' yíng', + '䁜' => ' huàng', + '䁛' => ' guì', + '䁚' => ' sǔn', + '䁙' => ' yǎn', + '䁘' => ' yǎo', + '䁗' => ' kǎi', + '䁖' => ' lōu', + '䁕' => ' mín', + '䁔' => ' xuān', + '䆄' => ' zhǎn', + '䆈' => ' zhì', + '㿊' => ' cǎn', + '䊺' => ' hù', + '䋄' => ' wǎng', + '䋃' => ' mào', + '䋂' => ' yáo', + '䋁' => ' gěng', + '䋀' => ' huà', + '䊿' => ' bó', + '䊾' => ' mù', + '䊽' => ' guài', + '䊼' => ' chǐ', + '䊻' => ' gān', + '䊶' => ' zhèn', + '䋉' => ' xué', + '䊵' => ' qiú', + '䊴' => ' qiàn', + '䊳' => ' mí', + '䊲' => ' chàn', + '䊱' => ' xiān', + '䊰' => ' chú', + '䊯' => ' kuàng', + '䊮' => ' dí', + '䊭' => ' dào', + '䊬' => ' chuā', + '䋈' => ' rú', + '䋊' => ' zhēng', + '䊪' => ' lì', + '䋚' => ' yì', + '䋦' => ' fán', + '䋥' => ' lí', + '䋤' => ' yuè', + '䋣' => ' fán', + '䋢' => ' biē', + '䋠' => ' bǔ', + '䋟' => ' jì', + '䋞' => ' wǎng', + '䋜' => ' qìng', + '䋛' => ' mǐ', + '䋙' => ' ěr', + '䋋' => ' mín', + '䋘' => ' chuò', + '䋖' => ' yù', + '䋕' => ' rèn', + '䋔' => ' bì', + '䋓' => ' zhòu', + '䋑' => ' liè', + '䋐' => ' yuè', + '䋏' => ' zuó', + '䋎' => ' zhàn', + '䋌' => ' jiǎng', + '䊫' => ' cuǐ', + '䊩' => ' fán', + '䋨' => ' fǔ', + '䉻' => ' qí', + '䊆' => ' jiù', + '䊅' => ' míng', + '䊄' => ' qióng', + '䊃' => ' pèi', + '䊂' => ' cè', + '䊀' => ' hú', + '䉿' => ' hú', + '䉾' => ' bì', + '䉽' => ' bǎn', + '䉼' => ' liào', + '䉺' => ' hóng', + '䊈' => ' méi', + '䉹' => ' líng', + '䉸' => ' biàn', + '䉷' => ' yán', + '䉶' => ' shuāng', + '䉵' => ' zhuàn', + '䉴' => ' ráng', + '䉳' => ' xiān', + '䉲' => ' mí', + '䉱' => ' ōu', + '䉰' => ' xiào', + '䊇' => ' bù', + '䊉' => ' sǎn', + '䊨' => ' luó', + '䊜' => ' tuán', + '䊧' => ' bì', + '䊦' => ' yè', + '䊥' => ' xiào', + '䊤' => ' tán', + '䊣' => ' huáng', + '䊡' => ' mán', + '䊠' => ' xì', + '䊟' => ' mén', + '䊞' => ' zhé', + '䊝' => ' xiè', + '䊛' => ' sà', + '䊊' => ' wèi', + '䊙' => ' yān', + '䊘' => ' jiù', + '䊗' => ' huáng', + '䊖' => ' nǎn', + '䊔' => ' yíng', + '䊓' => ' shì', + '䊑' => ' xiǎng', + '䊐' => ' hún', + '䊎' => ' quǎn', + '䊍' => ' lí', + '䋧' => ' qú', + '䋩' => ' ér', + '䉮' => ' lìn', + '䌬' => ' chóng', + '䌸' => ' juàn', + '䌷' => ' chōu', + '䌵' => ' zhú', + '䌴' => ' luò', + '䌳' => ' shī', + '䌱' => ' luò', + '䌰' => ' niè', + '䌯' => ' quān', + '䌮' => ' shuāng', + '䌭' => ' jiāo', + '䌫' => ' lǎn', + '䌺' => ' ěr', + '䌪' => ' yǎn', + '䌩' => ' miè', + '䌨' => ' cā', + '䌧' => ' chóu', + '䌦' => ' dào', + '䌥' => ' yǐn', + '䌤' => ' shī', + '䌣' => ' zuǎn', + '䌢' => ' líng', + '䌡' => ' tǐ', + '䌹' => ' jiǒng', + '䌻' => ' yì', + '䌟' => ' bó', + '䍈' => ' píng', + '䍓' => ' hù', + '䍒' => ' mǒu', + '䍑' => ' hǎn', + '䍐' => ' hǎn', + '䍎' => ' cùn', + '䍍' => ' kòu', + '䍌' => ' bù', + '䍋' => ' chuí', + '䍊' => ' jiāo', + '䍉' => ' zhǎi', + '䍇' => ' tà', + '䌼' => ' ruì', + '䍆' => ' zhù', + '䍅' => ' líng', + '䍄' => ' diǎn', + '䍃' => ' yóu', + '䍂' => ' yú', + '䍁' => ' suì', + '䍀' => ' lán', + '䌿' => ' fú', + '䌾' => ' rén', + '䌽' => ' cǎi', + '䌠' => ' jiān', + '䌞' => ' liǎn', + '䋪' => ' ē', + '䋶' => ' xǔ', + '䌁' => ' yāo', + '䌀' => ' kē', + '䋿' => ' wēi', + '䋾' => ' zhǎ', + '䋽' => ' běng', + '䋼' => ' tīng', + '䋻' => ' nín', + '䋹' => ' fú', + '䋸' => ' xún', + '䋷' => ' móu', + '䋵' => ' yì', + '䌃' => ' xiāo', + '䋴' => ' niù', + '䋳' => ' běi', + '䋲' => ' chě', + '䋱' => ' lái', + '䋰' => ' jú', + '䋯' => ' qǐ', + '䋮' => ' jìn', + '䋭' => ' yù', + '䋬' => ' tiān', + '䋫' => ' zhēng', + '䌂' => ' òu', + '䌄' => ' gěng', + '䌝' => ' jīn', + '䌒' => ' lù', + '䌜' => ' niè', + '䌛' => ' yáo', + '䌚' => ' sū', + '䌙' => ' huàng', + '䌘' => ' biè', + '䌗' => ' fǔ', + '䌖' => ' jié', + '䌕' => ' mí', + '䌔' => ' ōu', + '䌓' => ' fán', + '䌑' => ' jiān', + '䌅' => ' táng', + '䌐' => ' mì', + '䌏' => ' mì', + '䌎' => ' lüè', + '䌍' => ' jǐn', + '䌌' => ' qì', + '䌋' => ' dā', + '䌊' => ' yáo', + '䌈' => ' tā', + '䌇' => ' huì', + '䌆' => ' guì', + '䉯' => ' xiàn', + '䉭' => ' liè', + '䆉' => ' bà', + '䇓' => ' xū', + '䇠' => ' zhù', + '䇟' => ' jiàn', + '䇞' => ' gān', + '䇜' => ' qiǎn', + '䇛' => ' zhǐ', + '䇙' => ' yǐn', + '䇘' => ' hù', + '䇗' => ' zhōng', + '䇖' => ' yǔn', + '䇔' => ' luò', + '䇒' => ' jiè', + '䇢' => ' kǔ', + '䇑' => ' bà', + '䇐' => ' lì', + '䇏' => ' duì', + '䇎' => ' què', + '䇍' => ' chù', + '䇌' => ' qiào', + '䇋' => ' hài', + '䇈' => ' huà', + '䇇' => ' méng', + '䇅' => ' fá', + '䇡' => ' zhù', + '䇣' => ' niè', + '䇂' => ' qiān', + '䇰' => ' zhēng', + '䇼' => ' yì', + '䇻' => ' wěi', + '䇺' => ' dòu', + '䇹' => ' jùn', + '䇸' => ' chéng', + '䇷' => ' bié', + '䇶' => ' jué', + '䇵' => ' yí', + '䇲' => ' cè', + '䇱' => ' nà', + '䇯' => ' róng', + '䇤' => ' ruì', + '䇮' => ' rèn', + '䇭' => ' lǎo', + '䇬' => ' zhū', + '䇫' => ' jī', + '䇪' => ' chī', + '䇩' => ' yì', + '䇨' => ' gòng', + '䇧' => ' zhì', + '䇦' => ' ǎng', + '䇥' => ' zé', + '䇃' => ' sì', + '䇁' => ' sī', + '䇾' => ' yán', + '䆖' => ' hóng', + '䆠' => ' huàn', + '䆟' => ' kè', + '䆞' => ' yǎo', + '䆝' => ' xuè', + '䆜' => ' yòu', + '䆛' => ' zhà', + '䆚' => ' tóng', + '䆙' => ' yáo', + '䆘' => ' yā', + '䆗' => ' yǎo', + '䆕' => ' yuè', + '䆢' => ' yuè', + '䆔' => ' chōng', + '䆓' => ' è', + '䆒' => ' jiù', + '䆑' => ' chéng', + '䆐' => ' guó', + '䆏' => ' fèi', + '䆎' => ' xiān', + '䆍' => ' lóng', + '䆋' => ' qiū', + '䆊' => ' cuì', + '䆡' => ' láng', + '䆣' => ' chén', + '䇀' => ' róng', + '䆳' => ' qióng', + '䆿' => ' yì', + '䆾' => ' lán', + '䆽' => ' qú', + '䆻' => ' qiào', + '䆺' => ' pān', + '䆹' => ' chōng', + '䆸' => ' zhēng', + '䆷' => ' xuè', + '䆶' => ' jiū', + '䆵' => ' chéng', + '䆲' => ' kāng', + '䆦' => ' shèn', + '䆱' => ' tān', + '䆰' => ' yū', + '䆯' => ' zhuó', + '䆮' => ' jìn', + '䆭' => ' xuān', + '䆬' => ' yǔn', + '䆫' => ' chuāng', + '䆪' => ' hōng', + '䆩' => ' míng', + '䆨' => ' níng', + '䇽' => ' zhé', + '䈀' => ' sān', + '䉬' => ' fèi', + '䉅' => ' zhì', + '䉐' => ' kū', + '䉏' => ' xiè', + '䉎' => ' táng', + '䉍' => ' jiǎn', + '䉌' => ' suì', + '䉋' => ' mèi', + '䉊' => ' fàn', + '䉉' => ' gū', + '䉈' => ' sǎn', + '䉆' => ' diǎo', + '䉄' => ' léng', + '䉒' => ' fán', + '䉃' => ' jiǎng', + '䉂' => ' lěi', + '䉁' => ' líng', + '䉀' => ' shù', + '䈿' => ' mì', + '䈾' => ' shāo', + '䈽' => ' jīn', + '䈼' => ' miè', + '䈻' => ' pú', + '䈺' => ' zhōng', + '䉑' => ' wú', + '䉓' => ' luò', + '䈸' => ' hú', + '䉠' => ' wéi', + '䉫' => ' lí', + '䉪' => ' lèi', + '䉨' => ' yì', + '䉧' => ' liú', + '䉦' => ' qiān', + '䉥' => ' sǒng', + '䉤' => ' sǒu', + '䉣' => ' xiè', + '䉢' => ' sè', + '䉡' => ' tán', + '䉟' => ' huò', + '䉔' => ' cān', + '䉞' => ' dǎn', + '䉝' => ' yǐ', + '䉜' => ' zhì', + '䉛' => ' yù', + '䉚' => ' méng', + '䉙' => ' yún', + '䉘' => ' cóng', + '䉗' => ' yī', + '䉖' => ' líng', + '䉕' => ' céng', + '䈹' => ' sǒu', + '䈷' => ' luò', + '䈁' => ' lún', + '䈍' => ' máng', + '䈘' => ' cí', + '䈗' => ' suǒ', + '䈖' => ' kē', + '䈕' => ' shí', + '䈓' => ' gé', + '䈒' => ' nǎn', + '䈑' => ' guǎ', + '䈐' => ' guì', + '䈏' => ' báo', + '䈎' => ' yè', + '䈌' => ' qū', + '䈚' => ' tái', + '䈋' => ' tà', + '䈊' => ' líng', + '䈉' => ' shà', + '䈈' => ' féi', + '䈇' => ' zhào', + '䈆' => ' dài', + '䈅' => ' yù', + '䈄' => ' hán', + '䈃' => ' zhǎo', + '䈂' => ' píng', + '䈙' => ' zhòu', + '䈛' => ' kuài', + '䈶' => ' róng', + '䈫' => ' nà', + '䈵' => ' wēng', + '䈴' => ' qiàn', + '䈳' => ' tà', + '䈲' => ' bān', + '䈱' => ' tāo', + '䈰' => ' shāo', + '䈯' => ' zhēn', + '䈮' => ' jù', + '䈭' => ' sōu', + '䈬' => ' pú', + '䈪' => ' xì', + '䈜' => ' qìn', + '䈧' => ' wěi', + '䈦' => ' zōng', + '䈥' => ' jīn', + '䈤' => ' qián', + '䈣' => ' zhèng', + '䈢' => ' sǎi', + '䈡' => ' cōng', + '䈠' => ' huǎn', + '䈟' => ' cè', + '䈞' => ' dǔ', + '䈝' => ' xū', + '㿋' => ' sào', + '㿉' => ' tuǐ', + '㯠' => ' qiàn', + '㴦' => ' guàn', + '㴰' => ' néng', + '㴯' => ' zhī', + '㴮' => ' xiè', + '㴭' => ' yǎo', + '㴬' => ' xiè', + '㴫' => ' jùn', + '㴪' => ' niè', + '㴩' => ' yōng', + '㴨' => ' zhèn', + '㴧' => ' xī', + '㴥' => ' qiào', + '㴳' => ' lǒng', + '㴝' => ' lí', + '㴜' => ' biàn', + '㴛' => ' zhì', + '㴚' => ' suì', + '㴙' => ' zhǎ', + '㴘' => ' mào', + '㴗' => ' yōu', + '㴖' => ' luò', + '㴕' => ' jí', + '㴔' => ' xī', + '㴲' => ' sī', + '㴴' => ' chén', + '㴒' => ' yì', + '㵅' => ' tān', + '㵒' => ' fèi', + '㵑' => ' hè', + '㵐' => ' jué', + '㵏' => ' cuǐ', + '㵎' => ' jiàn', + '㵍' => ' mèn', + '㵌' => ' xún', + '㵋' => ' mì', + '㵊' => ' nà', + '㵆' => ' gǎo', + '㵄' => ' hàn', + '㴵' => ' mì', + '㵃' => ' shé', + '㵂' => ' shù', + '㵀' => ' zú', + '㴿' => ' dǐng', + '㴾' => ' bó', + '㴽' => ' xiè', + '㴼' => ' sù', + '㴸' => ' shǎn', + '㴷' => ' dān', + '㴶' => ' què', + '㴓' => ' shāi', + '㴑' => ' sù', + '㵔' => ' chě', + '㳛' => ' yú', + '㳫' => ' zǎn', + '㳪' => ' pì', + '㳩' => ' tān', + '㳨' => ' jiǎn', + '㳧' => ' chè', + '㳦' => ' xiè', + '㳥' => ' lòng', + '㳡' => ' guō', + '㳠' => ' tà', + '㳜' => ' xiū', + '㳚' => ' xù', + '㳭' => ' xián', + '㳙' => ' xuàn', + '㳘' => ' chōng', + '㳗' => ' chài', + '㳖' => ' yī', + '㳕' => ' lán', + '㳔' => ' duì', + '㳒' => ' biàn', + '㳑' => ' yì', + '㳐' => ' zhá', + '㳏' => ' shì', + '㳬' => ' xuán', + '㳮' => ' niào', + '㴐' => ' miàn', + '㴀' => ' fàn', + '㴏' => ' wǎng', + '㴋' => ' sù', + '㴉' => ' jǐ', + '㴈' => ' yìn', + '㴇' => ' shè', + '㴆' => ' jìn', + '㴄' => ' yǒng', + '㴃' => ' lèi', + '㴂' => ' tān', + '㴁' => ' yì', + '㳿' => ' xiè', + '㳴' => ' mì', + '㳾' => ' qiāng', + '㳽' => ' mǐ', + '㳼' => ' bì', + '㳻' => ' zé', + '㳺' => ' yóu', + '㳹' => ' wǎng', + '㳸' => ' huā', + '㳷' => ' hū', + '㳶' => ' nǒu', + '㳵' => ' jì', + '㵓' => ' shí', + '㵕' => ' shèn', + '㳍' => ' bù', + '㶥' => ' gān', + '㶴' => ' chǐ', + '㶳' => ' jìn', + '㶲' => ' yòng', + '㶰' => ' hán', + '㶯' => ' liù', + '㶭' => ' yǒu', + '㶬' => ' mò', + '㶫' => ' liǎo', + '㶧' => ' nèn', + '㶦' => ' jìn', + '㶤' => ' chǎo', + '㶶' => ' nóng', + '㶣' => ' chán', + '㶡' => ' dài', + '㶠' => ' yì', + '㶟' => ' lěi', + '㶞' => ' nǎng', + '㶛' => ' yú', + '㶚' => ' bà', + '㶘' => ' diàn', + '㶗' => ' fàn', + '㶖' => ' shù', + '㶵' => ' rèn', + '㶹' => ' hòng', + '㶔' => ' bèi', + '㷈' => ' è', + '㷔' => ' yàn', + '㷓' => ' zǒng', + '㷒' => ' yú', + '㷐' => ' huǐ', + '㷏' => ' yǒng', + '㷎' => ' hè', + '㷍' => ' lún', + '㷋' => ' tán', + '㷊' => ' fén', + '㷉' => ' wèi', + '㷇' => ' huī', + '㶺' => ' tiàn', + '㷆' => ' fù', + '㷅' => ' chǎo', + '㷄' => ' huǐ', + '㷃' => ' chuǐ', + '㷂' => ' shù', + '㷀' => ' qióng', + '㶿' => ' bó', + '㶾' => ' biāo', + '㶽' => ' guā', + '㶼' => ' āi', + '㶕' => ' jiǎn', + '㶓' => ' cáng', + '㵖' => ' nǜ', + '㵧' => ' gé', + '㵱' => ' piǎo', + '㵰' => ' xù', + '㵯' => ' féng', + '㵮' => ' chún', + '㵭' => ' zhǔ', + '㵬' => ' yíng', + '㵫' => ' nì', + '㵪' => ' xián', + '㵩' => ' yì', + '㵨' => ' pì', + '㵦' => ' suí', + '㵳' => ' liáo', + '㵥' => ' bì', + '㵤' => ' shà', + '㵣' => ' kě', + '㵢' => ' léi', + '㵡' => ' báo', + '㵠' => ' kū', + '㵞' => ' chóu', + '㵝' => ' yì', + '㵘' => ' màn', + '㵗' => ' píng', + '㵲' => ' wǔ', + '㵴' => ' cáng', + '㶒' => ' shǎn', + '㶄' => ' yán', + '㶑' => ' liàn', + '㶏' => ' yīn', + '㶎' => ' huán', + '㶍' => ' xiǎn', + '㶌' => ' lián', + '㶉' => ' xī', + '㶈' => ' yíng', + '㶇' => ' héng', + '㶆' => ' zhū', + '㶅' => ' xué', + '㶁' => ' guó', + '㵵' => ' zòu', + '㶀' => ' jiāo', + '㵿' => ' xiào', + '㵾' => ' qìng', + '㵽' => ' lěi', + '㵻' => ' xiū', + '㵺' => ' pài', + '㵹' => ' huán', + '㵸' => ' yào', + '㵷' => ' biàn', + '㵶' => ' zuō', + '㳎' => ' biàn', + '㳌' => ' yā', + '㷖' => ' zhào', + '㰭' => ' xū', + '㰷' => ' zì', + '㰶' => ' yǒu', + '㰵' => ' zú', + '㰴' => ' pǒu', + '㰳' => ' yà', + '㰲' => ' yū', + '㰱' => ' shà', + '㰰' => ' xiā', + '㰯' => ' kòu', + '㰮' => ' shèn', + '㰬' => ' xún', + '㰹' => ' xiān', + '㰫' => ' chān', + '㰪' => ' guī', + '㰩' => ' hāi', + '㰨' => ' xiā', + '㰧' => ' hāi', + '㰦' => ' qù', + '㰥' => ' xì', + '㰤' => ' hē', + '㰣' => ' zī', + '㰢' => ' kēng', + '㰸' => ' liǎn', + '㰺' => ' xià', + '㰠' => ' hāng', + '㱇' => ' sè', + '㱖' => ' cuì', + '㱔' => ' xiē', + '㱏' => ' zhèng', + '㱎' => ' kūn', + '㱍' => ' luán', + '㱌' => ' yé', + '㱋' => ' què', + '㱊' => ' yōu', + '㱉' => ' yè', + '㱈' => ' jìn', + '㱆' => ' xī', + '㰻' => ' yǐ', + '㱅' => ' yì', + '㱄' => ' hēi', + '㱃' => ' yǐn', + '㱂' => ' kāng', + '㱁' => ' shì', + '㱀' => ' chǐ', + '㰿' => ' xī', + '㰾' => ' jiào', + '㰽' => ' yàn', + '㰼' => ' shà', + '㰡' => ' xiè', + '㰟' => ' jì', + '㱘' => ' àn', + '㯯' => ' gòng', + '㯻' => ' gǔn', + '㯺' => ' jiàn', + '㯹' => ' biǎo', + '㯸' => ' jǐn', + '㯷' => ' pú', + '㯶' => ' zōng', + '㯳' => ' qíng', + '㯲' => ' jìn', + '㯱' => ' pāo', + '㯰' => ' zhé', + '㯮' => ' shú', + '㯿' => ' liè', + '㯭' => ' lǔ', + '㯬' => ' liǎn', + '㯫' => ' qú', + '㯪' => ' líng', + '㯩' => ' tì', + '㯦' => ' qí', + '㯥' => ' cáo', + '㯤' => ' lì', + '㯢' => ' zhèn', + '㯡' => ' pào', + '㯾' => ' zāo', + '㰀' => ' lí', + '㰞' => ' chī', + '㰐' => ' jué', + '㰝' => ' yǐ', + '㰛' => ' yuè', + '㰚' => ' lí', + '㰙' => ' nuó', + '㰘' => ' yí', + '㰗' => ' qí', + '㰖' => ' lǎn', + '㰔' => ' xiè', + '㰒' => ' xué', + '㰑' => ' shān', + '㰎' => ' zuì', + '㰁' => ' luǒ', + '㰍' => ' lóng', + '㰌' => ' què', + '㰋' => ' pín', + '㰊' => ' xián', + '㰈' => ' liǎn', + '㰆' => ' bèi', + '㰅' => ' dí', + '㰄' => ' jiàn', + '㰃' => ' mián', + '㰂' => ' shěn', + '㱗' => ' xiū', + '㱙' => ' xiǔ', + '㳋' => ' qiū', + '㲡' => ' nài', + '㲭' => ' tǎn', + '㲬' => ' jiāo', + '㲫' => ' pú', + '㲪' => ' dēng', + '㲨' => ' róng', + '㲧' => ' sào', + '㲦' => ' hàn', + '㲥' => ' táng', + '㲤' => ' shuāi', + '㲢' => ' biàn', + '㲠' => ' máo', + '㲰' => ' níng', + '㲟' => ' yǐng', + '㲞' => ' sū', + '㲝' => ' rǒng', + '㲜' => ' tán', + '㲛' => ' zhǐ', + '㲚' => ' shā', + '㲘' => ' qú', + '㲗' => ' fū', + '㲖' => ' xiāo', + '㲕' => ' lèi', + '㲯' => ' rán', + '㲱' => ' liè', + '㲓' => ' róng', + '㲿' => ' wǎng', + '㳊' => ' yōu', + '㳈' => ' pèi', + '㳇' => ' fù', + '㳆' => ' tǒu', + '㳅' => ' jiǎo', + '㳄' => ' xián', + '㳃' => ' cuì', + '㳂' => ' yán', + '㳁' => ' zè', + '㳀' => ' guò', + '㲾' => ' yǔ', + '㲲' => ' dié', + '㲽' => ' niàn', + '㲼' => ' yì', + '㲻' => ' nì', + '㲺' => ' jí', + '㲹' => ' guǐ', + '㲸' => ' xī', + '㲷' => ' dàn', + '㲶' => ' lǜ', + '㲴' => ' zhòng', + '㲳' => ' dié', + '㲔' => ' xiān', + '㲒' => ' bào', + '㱚' => ' cán', + '㱧' => ' wò', + '㱱' => ' huì', + '㱰' => ' zǎi', + '㱯' => ' ái', + '㱮' => ' kuài', + '㱭' => ' duàn', + '㱬' => ' wěi', + '㱫' => ' làn', + '㱪' => ' mèn', + '㱩' => ' dú', + '㱨' => ' liàn', + '㱦' => ' qī', + '㱳' => ' mò', + '㱥' => ' líng', + '㱤' => ' xī', + '㱣' => ' tuǐ', + '㱢' => ' láng', + '㱡' => ' shēng', + '㱠' => ' kū', + '㱟' => ' pī', + '㱞' => ' yì', + '㱜' => ' zhá', + '㱛' => ' chuǎn', + '㱲' => ' yì', + '㱴' => ' zì', + '㲏' => ' pāo', + '㲃' => ' jiù', + '㲎' => ' lóu', + '㲍' => ' zhī', + '㲌' => ' nèng', + '㲋' => ' chuò', + '㲊' => ' ruì', + '㲉' => ' què', + '㲈' => ' sháo', + '㲆' => ' líng', + '㲅' => ' jì', + '㲄' => ' jué', + '㲂' => ' chéng', + '㱵' => ' fèn', + '㲁' => ' kōng', + '㲀' => ' zhēn', + '㱿' => ' què', + '㱾' => ' gāi', + '㱽' => ' zhěn', + '㱼' => ' hāi', + '㱻' => ' luò', + '㱺' => ' lú', + '㱹' => ' lì', + '㱸' => ' bì', + '㱶' => ' péng', + '㷕' => ' qiú', + '㷗' => ' jiǒng', + '㿇' => ' xí', + '㼨' => ' hán', + '㼲' => ' liè', + '㼱' => ' ruǎn', + '㼰' => ' pí', + '㼯' => ' dòng', + '㼮' => ' chāi', + '㼭' => ' diàn', + '㼬' => ' xìng', + '㼫' => ' huàn', + '㼪' => ' jié', + '㼩' => ' chéng', + '㼧' => ' tóng', + '㼴' => ' ǒu', + '㼦' => ' gǒng', + '㼥' => ' tǒu', + '㼤' => ' qiè', + '㼣' => ' bó', + '㼢' => ' yí', + '㼡' => ' shū', + '㼠' => ' tuó', + '㼟' => ' bó', + '㼞' => ' pèng', + '㼝' => ' fàn', + '㼳' => ' shěng', + '㼵' => ' dì', + '㼛' => ' xíng', + '㽂' => ' sà', + '㽎' => ' tán', + '㽌' => ' liù', + '㽋' => ' luó', + '㽊' => ' xiè', + '㽉' => ' xiàn', + '㽈' => ' yì', + '㽇' => ' hú', + '㽆' => ' dāng', + '㽄' => ' sī', + '㽃' => ' pān', + '㽁' => ' lì', + '㼶' => ' yú', + '㽀' => ' zhèng', + '㼿' => ' tóng', + '㼾' => ' lù', + '㼽' => ' chuǎng', + '㼼' => ' piáo', + '㼻' => ' cóng', + '㼺' => ' táng', + '㼹' => ' kāng', + '㼸' => ' róng', + '㼷' => ' chuán', + '㼜' => ' àng', + '㼚' => ' gāng', + '㽑' => ' tán', + '㻪' => ' suì', + '㻶' => ' bǐ', + '㻵' => ' zhàn', + '㻲' => ' lǚ', + '㻱' => ' jīn', + '㻰' => ' miǎn', + '㻯' => ' tú', + '㻮' => ' càn', + '㻭' => ' sè', + '㻬' => ' tū', + '㻫' => ' bì', + '㻧' => ' duò', + '㻸' => ' zēn', + '㻡' => ' xuē', + '㻠' => ' tú', + '㻟' => ' suí', + '㻞' => ' bīn', + '㻝' => ' là', + '㻗' => ' bèi', + '㻖' => ' dài', + '㻕' => ' jué', + '㻔' => ' duǒ', + '㻓' => ' zōu', + '㻷' => ' jí', + '㻹' => ' xuān', + '㼙' => ' zhòu', + '㼎' => ' bó', + '㼘' => ' wǎ', + '㼗' => ' tíng', + '㼖' => ' lì', + '㼕' => ' dāng', + '㼔' => ' wēn', + '㼓' => ' lián', + '㼒' => ' tǎng', + '㼑' => ' liàn', + '㼐' => ' pián', + '㼏' => ' něi', + '㼍' => ' lěi', + '㻺' => ' lì', + '㼌' => ' yǔ', + '㼋' => ' gū', + '㼊' => ' tún', + '㼉' => ' zhèn', + '㼈' => ' luó', + '㼇' => ' qióng', + '㼂' => ' é', + '㻿' => ' shǔ', + '㻾' => ' yōng', + '㻽' => ' suì', + '㽏' => ' gàn', + '㽕' => ' yóu', + '㻑' => ' jì', + '㾜' => ' qiè', + '㾦' => ' pèi', + '㾥' => ' chù', + '㾤' => ' qiāng', + '㾣' => ' qīn', + '㾢' => ' ài', + '㾡' => ' què', + '㾠' => ' kuáng', + '㾟' => ' bù', + '㾞' => ' yóu', + '㾝' => ' chè', + '㾛' => ' qǐn', + '㾨' => ' yī', + '㾚' => ' xiē', + '㾙' => ' xìn', + '㾘' => ' gěng', + '㾗' => ' liàng', + '㾖' => ' lǐ', + '㾕' => ' shěn', + '㾔' => ' lǚ', + '㾓' => ' yuān', + '㾒' => ' rú', + '㾑' => ' dá', + '㾧' => ' kuò', + '㾩' => ' guāi', + '㾏' => ' jiè', + '㾹' => ' chái', + '㿆' => ' guō', + '㿅' => ' xiǎn', + '㿄' => ' ài', + '㿃' => ' zhì', + '㾿' => ' láng', + '㾾' => ' xiān', + '㾽' => ' zhuì', + '㾼' => ' tuǐ', + '㾻' => ' zhù', + '㾺' => ' mà', + '㾸' => ' gǎo', + '㾪' => ' shěng', + '㾷' => ' xī', + '㾶' => ' gǔ', + '㾵' => ' jì', + '㾴' => ' zhā', + '㾱' => ' bèi', + '㾰' => ' hú', + '㾯' => ' huī', + '㾮' => ' huáng', + '㾭' => ' zhòu', + '㾫' => ' piān', + '㾐' => ' lì', + '㾎' => ' yā', + '㽖' => ' nán', + '㽣' => ' yù', + '㽭' => ' ruǎn', + '㽬' => ' fù', + '㽫' => ' yōng', + '㽪' => ' zěng', + '㽩' => ' càn', + '㽨' => ' cuó', + '㽧' => ' zī', + '㽦' => ' xún', + '㽥' => ' róu', + '㽤' => ' jú', + '㽢' => ' ǎn', + '㽰' => ' shù', + '㽡' => ' bēi', + '㽠' => ' xiá', + '㽟' => ' liè', + '㽞' => ' liú', + '㽝' => ' lì', + '㽜' => ' wǎn', + '㽛' => ' gōu', + '㽚' => ' chì', + '㽙' => ' jùn', + '㽘' => ' gǎng', + '㽯' => ' xí', + '㽱' => ' jiǎo', + '㾍' => ' nái', + '㾂' => ' hāi', + '㾌' => ' xuǎn', + '㾋' => ' xiū', + '㾊' => ' jí', + '㾉' => ' líng', + '㾈' => ' fù', + '㾇' => ' mù', + '㾆' => ' rán', + '㾅' => ' zǐ', + '㾄' => ' dú', + '㾃' => ' tuó', + '㾁' => ' shù', + '㽲' => ' jiǎo', + '㾀' => ' qiè', + '㽾' => ' wù', + '㽽' => ' gù', + '㽻' => ' zhī', + '㽺' => ' jí', + '㽹' => ' fǎn', + '㽸' => ' chén', + '㽷' => ' shuì', + '㽴' => ' zhàng', + '㽳' => ' xū', + '㻒' => ' jùn', + '㻏' => ' líng', + '㷘' => ' tái', + '㸫' => ' qián', + '㸶' => ' yān', + '㸵' => ' guǐ', + '㸳' => ' líng', + '㸲' => ' zuó', + '㸱' => ' tuó', + '㸰' => ' tuó', + '㸯' => ' kē', + '㸮' => ' fén', + '㸭' => ' bā', + '㸬' => ' bèi', + '㸪' => ' chún', + '㸸' => ' hǒu', + '㸩' => ' ān', + '㸨' => ' jiū', + '㸧' => ' kèn', + '㸦' => ' hù', + '㸥' => ' chàn', + '㸤' => ' piàn', + '㸣' => ' yè', + '㸢' => ' bèi', + '㸡' => ' shū', + '㸠' => ' tiǎo', + '㸷' => ' shì', + '㸹' => ' liè', + '㸞' => ' zhé', + '㹇' => ' hé', + '㹑' => ' sì', + '㹐' => ' chóng', + '㹏' => ' jǐn', + '㹎' => ' léi', + '㹍' => ' dí', + '㹌' => ' chǎn', + '㹋' => ' xiū', + '㹊' => ' yuè', + '㹉' => ' yuán', + '㹈' => ' lí', + '㹆' => ' huī', + '㸺' => ' shā', + '㹅' => ' zǒng', + '㹄' => ' jì', + '㹃' => ' fèi', + '㹂' => ' qiǎn', + '㹁' => ' liáng', + '㹀' => ' bó', + '㸿' => ' dú', + '㸾' => ' rèn', + '㸽' => ' bèi', + '㸻' => ' sì', + '㸟' => ' zhī', + '㸝' => ' xiān', + '㹓' => ' yǎo', + '㷯' => ' bèng', + '㷼' => ' yàn', + '㷻' => ' wú', + '㷹' => ' zhào', + '㷸' => ' dié', + '㷷' => ' juǎn', + '㷶' => ' bèi', + '㷵' => ' mò', + '㷴' => ' gé', + '㷳' => ' yàn', + '㷰' => ' chī', + '㷮' => ' zāo', + '㷿' => ' xiān', + '㷬' => ' mò', + '㷫' => ' qǐng', + '㷪' => ' cuì', + '㷦' => ' xù', + '㷤' => ' hù', + '㷣' => ' xīng', + '㷢' => ' zhǎ', + '㷡' => ' jiǒng', + '㷠' => ' lín', + '㷟' => ' tuì', + '㷾' => ' jué', + '㸀' => ' tái', + '㸜' => ' kòng', + '㸐' => ' rán', + '㸛' => ' sháo', + '㸚' => ' lǐ', + '㸙' => ' zhē', + '㸘' => ' wàn', + '㸗' => ' tóng', + '㸖' => ' qū', + '㸕' => ' jué', + '㸓' => ' mì', + '㸒' => ' yín', + '㸑' => ' cuàn', + '㸏' => ' mí', + '㸁' => ' hǎn', + '㸎' => ' niè', + '㸍' => ' xì', + '㸌' => ' huò', + '㸋' => ' fán', + '㸊' => ' lài', + '㸉' => ' xiè', + '㸇' => ' zuǎn', + '㸅' => ' jié', + '㸄' => ' jì', + '㸃' => ' diǎn', + '㹒' => ' pǔ', + '㹔' => ' jiāng', + '㻎' => ' lì', + '㺝' => ' hàn', + '㺨' => ' sī', + '㺦' => ' lián', + '㺥' => ' chán', + '㺤' => ' xiān', + '㺣' => ' xī', + '㺢' => ' huò', + '㺡' => ' lì', + '㺠' => ' yòu', + '㺟' => ' zhuó', + '㺞' => ' yú', + '㺜' => ' nóng', + '㺪' => ' pú', + '㺛' => ' zhù', + '㺚' => ' tǎ', + '㺘' => ' zhàn', + '㺗' => ' chān', + '㺖' => ' hǎn', + '㺕' => ' fán', + '㺔' => ' hài', + '㺓' => ' zé', + '㺒' => ' xiāo', + '㺑' => ' shān', + '㺩' => ' jiù', + '㺫' => ' qiú', + '㺏' => ' lóu', + '㺿' => ' yí', + '㻍' => ' wú', + '㻌' => ' tú', + '㻋' => ' là', + '㻊' => ' máng', + '㻉' => ' bù', + '㻅' => ' huì', + '㻄' => ' bǎo', + '㻃' => ' qū', + '㻂' => ' píng', + '㻀' => ' yú', + '㺺' => ' mào', + '㺬' => ' gǒng', + '㺹' => ' biàn', + '㺸' => ' píng', + '㺷' => ' xù', + '㺵' => ' jiú', + '㺴' => ' bā', + '㺳' => ' méi', + '㺲' => ' niǔ', + '㺱' => ' réng', + '㺮' => ' yú', + '㺭' => ' zǐ', + '㺐' => ' lǎo', + '㺎' => ' róng', + '㹕' => ' huān', + '㹡' => ' xuán', + '㹮' => ' mò', + '㹭' => ' yì', + '㹬' => ' shǐ', + '㹫' => ' yí', + '㹨' => ' yòu', + '㹦' => ' diāo', + '㹥' => ' zhù', + '㹤' => ' qiè', + '㹣' => ' zhōng', + '㹢' => ' jiā', + '㹠' => ' tún', + '㹲' => ' xiāo', + '㹟' => ' jué', + '㹞' => ' yín', + '㹝' => ' shì', + '㹜' => ' yín', + '㹛' => ' ráo', + '㹚' => ' yíng', + '㹙' => ' wěng', + '㹘' => ' rù', + '㹗' => ' tāo', + '㹖' => ' huàn', + '㹱' => ' què', + '㹳' => ' wú', + '㺍' => ' pín', + '㺁' => ' nǎo', + '㺌' => ' xiàn', + '㺋' => ' wēng', + '㺊' => ' yàng', + '㺉' => ' hù', + '㺈' => ' chī', + '㺇' => ' sī', + '㺅' => ' hóu', + '㺄' => ' yǔ', + '㺃' => ' gǒu', + '㺂' => ' yán', + '㺀' => ' hū', + '㹴' => ' gēng', + '㹿' => ' zhuó', + '㹾' => ' piǎo', + '㹽' => ' chǎn', + '㹼' => ' jú', + '㹻' => ' wō', + '㹺' => ' tà', + '㹹' => ' gēng', + '㹸' => ' ní', + '㹷' => ' shǐ', + '㹶' => ' tíng', + '㹵' => ' yǐng', + '冊' => ' cè', + '册' => ' cè', + '殘' => ' cán', + '拥' => ' yōng', + '拯' => ' zhěng', + '拮' => ' jié', + '拭' => ' shì', + '括' => ' kuò', + '拫' => ' hén', + '拪' => ' qiān', + '择' => ' zé', + '拨' => ' bō', + '拧' => ' níng', + '拦' => ' lán', + '拤' => ' qiá', + '拱' => ' gǒng', + '拣' => ' jiǎn', + '拢' => ' lǒng', + '拡' => ' kuò', + '拠' => ' jù', + '拟' => ' nǐ', + '拞' => ' dǐ', + '拝' => ' bài', + '拜' => ' bài', + '招' => ' zhāo', + '拚' => ' pàn', + '拰' => ' nǐn', + '拲' => ' gǒng', + '拘' => ' jū', + '拿' => ' ná', + '按' => ' àn', + '挈' => ' qiè', + '指' => ' zhǐ', + '挆' => ' duǒ', + '挅' => ' duǒ', + '挄' => ' kuò', + '挃' => ' zhì', + '挂' => ' guà', + '持' => ' chí', + '挀' => ' bāi', + '拾' => ' shí', + '拳' => ' quán', + '拽' => ' zhuāi', + '拼' => ' pīn', + '拻' => ' huī', + '拺' => ' cè', + '拹' => ' xié', + '拸' => ' yí', + '拷' => ' kǎo', + '拶' => ' zā', + '拵' => ' cún', + '拴' => ' shuān', + '拙' => ' zhuō', + '拗' => ' ǎo', + '挋' => ' zhèn', + '抱' => ' bào', + '抻' => ' chēn', + '抺' => ' mèi', + '抹' => ' mǒ', + '抸' => ' jiā', + '抷' => ' pī', + '抶' => ' chì', + '抵' => ' dǐ', + '抴' => ' yè', + '抳' => ' nǐ', + '抲' => ' hē', + '抰' => ' yāng', + '抽' => ' chōu', + '抯' => ' zhā', + '抮' => ' zhěn', + '抭' => ' yǎo', + '抬' => ' tái', + '披' => ' pī', + '抪' => ' bù', + '抩' => ' tān', + '抨' => ' pēng', + '抧' => ' zhǐ', + '抦' => ' bǐng', + '押' => ' yā', + '抾' => ' qū', + '拖' => ' tuō', + '拋' => ' pāo', + '拕' => ' tuō', + '拔' => ' bá', + '拓' => ' tà', + '拒' => ' jù', + '拑' => ' qián', + '拐' => ' guǎi', + '拏' => ' ná', + '拎' => ' līn', + '拍' => ' pāi', + '拌' => ' bàn', + '拊' => ' fǔ', + '抿' => ' mǐn', + '拉' => ' lā', + '拈' => ' niān', + '拇' => ' mǔ', + '拆' => ' chāi', + '担' => ' dān', + '拄' => ' zhǔ', + '拃' => ' zhǎ', + '拂' => ' fú', + '拁' => ' jiā', + '拀' => ' chù', + '挊' => ' nòng', + '挌' => ' gé', + '护' => ' hù', + '捍' => ' hàn', + '捗' => ' bù', + '捖' => ' wán', + '捕' => ' bǔ', + '捔' => ' jué', + '捓' => ' yé', + '捒' => ' shù', + '捑' => ' zè', + '捐' => ' juān', + '捏' => ' niē', + '捎' => ' shāo', + '捌' => ' bā', + '捙' => ' yì', + '捋' => ' lǚ', + '捊' => ' póu', + '捉' => ' zhuō', + '捈' => ' tú', + '捇' => ' huò', + '捆' => ' kǔn', + '捅' => ' tǒng', + '捄' => ' jiù', + '捃' => ' jùn', + '捂' => ' wǔ', + '捘' => ' zùn', + '捚' => ' zhāi', + '捀' => ' féng', + '捧' => ' pěng', + '捱' => ' ái', + '捰' => ' wǒ', + '捯' => ' dáo', + '据' => ' jù', + '捭' => ' bǎi', + '捬' => ' fǔ', + '捫' => ' mén', + '捪' => ' mín', + '捩' => ' liè', + '捨' => ' shě', + '捦' => ' qín', + '捛' => ' lǚ', + '捥' => ' wàn', + '捤' => ' wei', + '捣' => ' dǎo', + '换' => ' huàn', + '捡' => ' jiǎn', + '捠' => ' bāng', + '损' => ' sǔn', + '捞' => ' lāo', + '捝' => ' tuō', + '捜' => ' sōu', + '捁' => ' jiǎo', + '挿' => ' chā', + '挍' => ' jiào', + '挙' => ' jǔ', + '挣' => ' zhēng', + '挢' => ' jiǎo', + '挡' => ' dǎng', + '挠' => ' náo', + '挟' => ' xié', + '挞' => ' tà', + '挝' => ' wō', + '挜' => ' yà', + '挛' => ' luán', + '挚' => ' zhì', + '挘' => ' lie', + '挥' => ' huī', + '挗' => ' jué', + '挖' => ' wā', + '挕' => ' dié', + '挔' => ' lǚ', + '挓' => ' zhā', + '挒' => ' liè', + '挑' => ' tiāo', + '挐' => ' ná', + '挏' => ' dòng', + '挎' => ' kuà', + '挤' => ' jǐ', + '挦' => ' xián', + '挾' => ' xié', + '挳' => ' kēng', + '挽' => ' wǎn', + '挼' => ' ruá', + '挻' => ' shān', + '挺' => ' tǐng', + '挹' => ' yì', + '挸' => ' jiǎn', + '挷' => ' péng', + '挶' => ' jū', + '挵' => ' lòng', + '挴' => ' měi', + '挲' => ' sā', + '挧' => ' yu', + '挱' => ' sā', + '挰' => ' chéng', + '振' => ' zhèn', + '挮' => ' tǐ', + '挭' => ' gěng', + '挬' => ' bó', + '挫' => ' cuò', + '挪' => ' nuó', + '挩' => ' tuō', + '挨' => ' āi', + '报' => ' bào', + '抣' => ' yun', + '捳' => ' yuè', + '戕' => ' qiāng', + '戟' => ' jǐ', + '戞' => ' jiá', + '戝' => ' zéi', + '戜' => ' dié', + '戛' => ' jiá', + '戚' => ' qī', + '戙' => ' dòng', + '战' => ' zhàn', + '戗' => ' qiāng', + '或' => ' huò', + '戔' => ' jiān', + '戡' => ' kān', + '戓' => ' gē', + '戒' => ' jiè', + '我' => ' wǒ', + '成' => ' chéng', + '戏' => ' xì', + '戎' => ' róng', + '戍' => ' shù', + '戌' => ' xū', + '戋' => ' jiān', + '戊' => ' wù', + '戠' => ' zhī', + '戢' => ' jí', + '戈' => ' gē', + '戯' => ' hū', + '戹' => ' è', + '戸' => ' hù', + '户' => ' hù', + '戶' => ' hù', + '戵' => ' qú', + '戴' => ' dài', + '戳' => ' chuō', + '戲' => ' xì', + '戱' => ' xì', + '戰' => ' zhàn', + '戮' => ' lù', + '戣' => ' kuí', + '戭' => ' yǎn', + '戬' => ' jiǎn', + '戫' => ' yù', + '截' => ' jié', + '戩' => ' jiǎn', + '戨' => ' gē', + '戧' => ' qiāng', + '戦' => ' zhàn', + '戥' => ' děng', + '戤' => ' gài', + '戉' => ' yuè', + '戇' => ' zhuàng', + '戻' => ' tì', + '懡' => ' mǒ', + '懫' => ' zhì', + '懪' => ' bó', + '懩' => ' yǎng', + '懨' => ' yān', + '懧' => ' nuò', + '懦' => ' nuò', + '懥' => ' zhì', + '懤' => ' chóu', + '懣' => ' mèn', + '懢' => ' lán', + '懠' => ' qí', + '懭' => ' kuǎng', + '懟' => ' duì', + '懞' => ' méng', + '懝' => ' ài', + '懜' => ' měng', + '懛' => ' dāi', + '懚' => ' yìn', + '懙' => ' yǔ', + '懘' => ' chì', + '懗' => ' xià', + '懖' => ' kuò', + '懬' => ' kuàng', + '懮' => ' yǒu', + '戆' => ' gàng', + '懻' => ' jì', + '戅' => ' gàng', + '戄' => ' jué', + '戃' => ' tǎng', + '戂' => ' mí', + '戁' => ' nǎn', + '戀' => ' liàn', + '懿' => ' yì', + '懾' => ' shè', + '懽' => ' huān', + '懼' => ' jù', + '懺' => ' chàn', + '懯' => ' fū', + '懹' => ' ràng', + '懸' => ' xuán', + '懷' => ' huái', + '懶' => ' lǎn', + '懵' => ' měng', + '懴' => ' chàn', + '懳' => ' hui', + '懲' => ' chéng', + '懱' => ' miè', + '懰' => ' liú', + '戺' => ' shì', + '戼' => ' mǎo', + '抢' => ' qiǎng', + '扽' => ' dèn', + '抇' => ' hú', + '抆' => ' wěn', + '抅' => ' jū', + '抄' => ' chāo', + '抃' => ' biàn', + '抂' => ' kuáng', + '抁' => ' yǎn', + '技' => ' jì', + '承' => ' chéng', + '找' => ' zhǎo', + '扼' => ' è', + '抉' => ' jué', + '扻' => ' zhì', + '扺' => ' zhǐ', + '批' => ' pī', + '扸' => ' xī', + '扷' => ' ào', + '扶' => ' fú', + '扵' => ' yú', + '扴' => ' jiá', + '扳' => ' bān', + '扲' => ' qián', + '抈' => ' yuè', + '把' => ' bǎ', + '扰' => ' rǎo', + '抗' => ' kàng', + '抡' => ' lūn', + '抠' => ' kōu', + '抟' => ' tuán', + '択' => ' zé', + '抝' => ' ǎo', + '抜' => ' bá', + '抛' => ' pāo', + '抚' => ' fǔ', + '抙' => ' póu', + '折' => ' zhé', + '抖' => ' dǒu', + '抋' => ' qìn', + '投' => ' tóu', + '抔' => ' póu', + '抓' => ' zhuā', + '抒' => ' shū', + '抑' => ' yì', + '抐' => ' nè', + '抏' => ' wán', + '抎' => ' yǔn', + '抍' => ' zhěng', + '抌' => ' dǎn', + '扱' => ' xī', + '扯' => ' chě', + '戽' => ' hù', + '扉' => ' fēi', + '打' => ' dǎ', + '扒' => ' bā', + '扑' => ' pū', + '扐' => ' lè', + '扏' => ' qiú', + '扎' => ' zhā', + '才' => ' cái', + '扌' => ' shou', + '手' => ' shǒu', + '扊' => ' yǎn', + '扈' => ' hù', + '払' => ' fǎn', + '扇' => ' shàn', + '扆' => ' yǐ', + '扅' => ' yí', + '扄' => ' shǎng', + '扃' => ' jiōng', + '扂' => ' diàn', + '扁' => ' biǎn', + '所' => ' suǒ', + '房' => ' fáng', + '戾' => ' lì', + '扔' => ' rēng', + '扖' => ' ru', + '扮' => ' bàn', + '扣' => ' kòu', + '扭' => ' niǔ', + '扬' => ' yáng', + '扫' => ' sǎo', + '扪' => ' mén', + '扩' => ' kuò', + '扨' => ' rèn', + '执' => ' zhí', + '扦' => ' qiān', + '扥' => ' dèn', + '扤' => ' wù', + '扢' => ' gǔ', + '扗' => ' zài', + '扡' => ' tuō', + '扠' => ' chā', + '扟' => ' shēn', + '扞' => ' gǎn', + '扝' => ' kū', + '扜' => ' yū', + '扛' => ' káng', + '扚' => ' diǎo', + '扙' => ' zhàng', + '托' => ' tuō', + '捲' => ' juǎn', + '捴' => ' zǒng', + '懔' => ' lǐn', + '撆' => ' piē', + '撐' => ' chēng', + '撏' => ' xián', + '撎' => ' yì', + '撍' => ' zǎn', + '撌' => ' guì', + '撋' => ' ruán', + '撊' => ' xiàn', + '撉' => ' dūn', + '撈' => ' lāo', + '撇' => ' piē', + '撅' => ' juē', + '撒' => ' sā', + '撄' => ' yīng', + '撃' => ' jí', + '撂' => ' liào', + '撁' => ' qiān', + '撀' => ' gòu', + '摿' => ' yīn', + '摾' => ' jiàng', + '摽' => ' biāo', + '摼' => ' kēng', + '摻' => ' càn', + '撑' => ' chēng', + '撓' => ' náo', + '摹' => ' mó', + '撠' => ' jǐ', + '撪' => ' bèn', + '撩' => ' liāo', + '撨' => ' fǔ', + '撧' => ' juē', + '撦' => ' chě', + '撥' => ' bō', + '撤' => ' chè', + '撣' => ' dǎn', + '撢' => ' dǎn', + '撡' => ' cāo', + '撟' => ' jiǎo', + '撔' => ' hòng', + '撞' => ' zhuàng', + '撝' => ' huī', + '撜' => ' zhěng', + '撛' => ' lǐn', + '撚' => ' niǎn', + '撙' => ' zǔn', + '撘' => ' dā', + '撗' => ' guàng', + '撖' => ' hàn', + '撕' => ' sī', + '摺' => ' zhé', + '摸' => ' mō', + '撬' => ' qiào', + '摒' => ' bǐng', + '摜' => ' guàn', + '摛' => ' chī', + '摚' => ' chēng', + '摙' => ' liǎn', + '摘' => ' zhāi', + '摗' => ' sōu', + '摖' => ' qì', + '摕' => ' dì', + '摔' => ' shuāi', + '摓' => ' féng', + '摑' => ' guāi', + '摞' => ' luò', + '摐' => ' chuāng', + '摏' => ' chōng', + '摎' => ' jiū', + '摍' => ' suō', + '摌' => ' chǎn', + '摋' => ' sà', + '摊' => ' tān', + '摉' => ' sōu', + '摈' => ' bìn', + '摇' => ' yáo', + '摝' => ' lù', + '摟' => ' lǒu', + '摷' => ' jiǎo', + '摬' => ' yǐng', + '摶' => ' tuán', + '摵' => ' shè', + '摴' => ' chū', + '摳' => ' kōu', + '摲' => ' chàn', + '摱' => ' màn', + '摰' => ' niè', + '摯' => ' zhì', + '摮' => ' áo', + '摭' => ' zhí', + '摫' => ' guī', + '摠' => ' zǒng', + '摪' => ' jiāng', + '摩' => ' mó', + '摨' => ' nái', + '摧' => ' cuī', + '摦' => ' huà', + '摥' => ' tàng', + '摤' => ' chuǎng', + '摣' => ' zhā', + '摢' => ' hù', + '摡' => ' gài', + '撫' => ' fǔ', + '播' => ' bō', + '摅' => ' shū', + '擮' => ' jí', + '擸' => ' liè', + '擷' => ' xié', + '擶' => ' jiàn', + '擵' => ' mó', + '擴' => ' kuò', + '擳' => ' zhì', + '擲' => ' zhì', + '擱' => ' gē', + '擰' => ' níng', + '擯' => ' bìn', + '擭' => ' wò', + '擺' => ' bǎi', + '擬' => ' nǐ', + '擫' => ' yè', + '擪' => ' yè', + '擩' => ' rǔ', + '擨' => ' yé', + '擧' => ' jǔ', + '擦' => ' cā', + '擥' => ' lǎn', + '擤' => ' xǐng', + '擣' => ' dǎo', + '擹' => ' tān', + '擻' => ' sǒu', + '擡' => ' tái', + '攈' => ' jùn', + '攒' => ' zǎn', + '攑' => ' qiān', + '攐' => ' qiān', + '攏' => ' lǒng', + '攎' => ' lú', + '攍' => ' yíng', + '攌' => ' huǎn', + '攋' => ' là', + '攊' => ' lì', + '攉' => ' huō', + '攇' => ' xiǎn', + '擼' => ' lǔ', + '攆' => ' niǎn', + '攅' => ' zǎn', + '攄' => ' shū', + '攃' => ' cā', + '攂' => ' lèi', + '攁' => ' yǎng', + '攀' => ' pān', + '擿' => ' tī', + '擾' => ' rǎo', + '擽' => ' lüè', + '擢' => ' zhuó', + '擠' => ' jǐ', + '撮' => ' cuō', + '撺' => ' cuān', + '擄' => ' lǔ', + '擃' => ' nǎng', + '擂' => ' léi', + '擁' => ' yōng', + '擀' => ' gǎn', + '撿' => ' jiǎn', + '撾' => ' wō', + '撽' => ' qiào', + '撼' => ' hàn', + '撻' => ' tà', + '撹' => ' jiǎo', + '擆' => ' zhuó', + '撸' => ' lū', + '撷' => ' xié', + '撶' => ' huá', + '撵' => ' niǎn', + '撴' => ' dūn', + '撳' => ' qìn', + '撲' => ' pū', + '撱' => ' wěi', + '撰' => ' zhuàn', + '撯' => ' zhuó', + '擅' => ' shàn', + '擇' => ' zé', + '擟' => ' mí', + '擔' => ' dān', + '擞' => ' sǒu', + '擝' => ' meng', + '擜' => ' e', + '擛' => ' yè', + '據' => ' jù', + '擙' => ' ào', + '擘' => ' bāi', + '擗' => ' pǐ', + '擖' => ' kā', + '擕' => ' xié', + '擓' => ' kuǎi', + '擈' => ' pū', + '擒' => ' qín', + '擑' => ' jiē', + '擐' => ' huàn', + '擏' => ' qíng', + '擎' => ' qíng', + '操' => ' cāo', + '擌' => ' sè', + '擋' => ' dǎng', + '擊' => ' jī', + '擉' => ' chuò', + '摆' => ' bǎi', + '摄' => ' shè', + '捵' => ' chēn', + '掵' => ' ming', + '掿' => ' nuò', + '掾' => ' yuàn', + '掽' => ' pèng', + '掼' => ' guàn', + '掻' => ' sāo', + '掺' => ' càn', + '掹' => ' meng', + '掸' => ' dǎn', + '掷' => ' zhì', + '掶' => ' geng', + '掴' => ' guāi', + '揁' => ' zhēng', + '掳' => ' lǔ', + '掲' => ' jiē', + '掱' => ' pá', + '掰' => ' bāi', + '掯' => ' kèn', + '掮' => ' qián', + '掭' => ' tiàn', + '掬' => ' jū', + '掫' => ' zhōu', + '措' => ' cuò', + '揀' => ' jiǎn', + '揂' => ' jiū', + '推' => ' tuī', + '描' => ' miáo', + '揙' => ' biān', + '揘' => ' yóng', + '揗' => ' xún', + '揖' => ' yī', + '揕' => ' zhèn', + '揔' => ' zǒng', + '揓' => ' shì', + '插' => ' chā', + '揑' => ' niē', + '提' => ' tí', + '揎' => ' xuān', + '揃' => ' jiǎn', + '揍' => ' zòu', + '揌' => ' sāi', + '揋' => ' wēi', + '揊' => ' pì', + '揉' => ' róu', + '揈' => ' hōng', + '揇' => ' nǎn', + '揆' => ' kuí', + '揅' => ' yán', + '揄' => ' yú', + '掩' => ' yǎn', + '控' => ' kòng', + '換' => ' huàn', + '掁' => ' chéng', + '掋' => ' dǐ', + '掊' => ' póu', + '掉' => ' diào', + '授' => ' shòu', + '掇' => ' duō', + '掆' => ' gāng', + '掅' => ' qìng', + '掄' => ' lūn', + '掃' => ' sǎo', + '掂' => ' diān', + '掀' => ' xiān', + '掍' => ' hùn', + '捿' => ' xī', + '捾' => ' wò', + '捽' => ' zuó', + '捼' => ' ruó', + '捻' => ' niǎn', + '捺' => ' nà', + '捹' => ' bèn', + '捸' => ' tū', + '捷' => ' jié', + '捶' => ' chuí', + '掌' => ' zhǎng', + '掎' => ' jǐ', + '掦' => ' tì', + '掛' => ' guà', + '接' => ' jiē', + '掤' => ' bīng', + '掣' => ' chè', + '探' => ' tàn', + '採' => ' cǎi', + '掠' => ' lüè', + '掟' => ' zhěng', + '掞' => ' shàn', + '掝' => ' huò', + '掜' => ' yì', + '掚' => ' liǎng', + '掏' => ' tāo', + '掙' => ' zhēng', + '掘' => ' jué', + '掗' => ' yà', + '掖' => ' yē', + '掕' => ' líng', + '掔' => ' qiān', + '掓' => ' shū', + '排' => ' pái', + '掑' => ' qí', + '掐' => ' qiā', + '揚' => ' yáng', + '揜' => ' yǎn', + '摃' => ' káng', + '搞' => ' gǎo', + '搨' => ' tà', + '搧' => ' shān', + '搦' => ' nuò', + '搥' => ' chuí', + '搤' => ' è', + '搣' => ' miè', + '搢' => ' jìn', + '搡' => ' sǎng', + '搠' => ' shuò', + '搟' => ' xiǎn', + '搝' => ' qiǔ', + '搪' => ' táng', + '搜' => ' sōu', + '搛' => ' jiān', + '搚' => ' lā', + '搙' => ' nù', + '搘' => ' zhī', + '搗' => ' dǎo', + '搖' => ' yáo', + '搕' => ' kē', + '搔' => ' sāo', + '搓' => ' cuō', + '搩' => ' zhǎ', + '搫' => ' pán', + '搑' => ' róng', + '搸' => ' zhēn', + '摂' => ' shè', + '摁' => ' èn', + '摀' => ' wǔ', + '搿' => ' gé', + '搾' => ' zhà', + '搽' => ' chá', + '搼' => ' quán', + '搻' => ' nuò', + '携' => ' xié', + '搹' => ' è', + '搷' => ' tián', + '搬' => ' bān', + '搶' => ' qiǎng', + '搵' => ' wèn', + '搴' => ' qiān', + '搳' => ' huá', + '搲' => ' wā', + '搱' => ' zhì', + '搰' => ' hú', + '搯' => ' tāo', + '搮' => ' lì', + '搭' => ' dā', + '搒' => ' bàng', + '搐' => ' chù', + '揝' => ' zǎn', + '揩' => ' kāi', + '揳' => ' xiē', + '揲' => ' dié', + '揱' => ' xiāo', + '揰' => ' chòng', + '揯' => ' gèn', + '揮' => ' huī', + '揭' => ' jiē', + '揬' => ' tú', + '揫' => ' jiū', + '揪' => ' jiū', + '揨' => ' chén', + '揵' => ' qián', + '揧' => ' là', + '揦' => ' lá', + '揥' => ' tì', + '揤' => ' jí', + '揣' => ' chuāi', + '揢' => ' ké', + '握' => ' wò', + '揠' => ' yà', + '揟' => ' xū', + '揞' => ' ǎn', + '援' => ' yuán', + '揶' => ' yé', + '搏' => ' bó', + '搄' => ' gēng', + '搎' => ' sūn', + '損' => ' sǔn', + '搌' => ' zhǎn', + '搋' => ' chuāi', + '搊' => ' chōu', + '搉' => ' què', + '搈' => ' róng', + '搇' => ' qìn', + '搆' => ' gòu', + '搅' => ' jiǎo', + '搃' => ' zǒng', + '揷' => ' chā', + '搂' => ' lǒu', + '搁' => ' gē', + '搀' => ' chān', + '揿' => ' qìn', + '揾' => ' wèn', + '揽' => ' lǎn', + '揼' => ' beng', + '揻' => ' wēi', + '揺' => ' yáo', + '揹' => ' bēi', + '揸' => ' zhā', + '懕' => ' yān', + '懓' => ' ài', + '攔' => ' lán', + '徤' => ' jiàn', + '微' => ' wēi', + '徭' => ' yáo', + '徬' => ' páng', + '徫' => ' wěi', + '循' => ' xún', + '復' => ' fù', + '徨' => ' huáng', + '徧' => ' biàn', + '徦' => ' jiǎ', + '徥' => ' shì', + '徣' => ' jiè', + '徰' => ' zhēng', + '徢' => ' xiè', + '御' => ' yù', + '徠' => ' lái', + '徟' => ' zhōu', + '從' => ' cóng', + '徝' => ' zhì', + '徜' => ' cháng', + '徛' => ' jì', + '徚' => ' dōng', + '徙' => ' xǐ', + '徯' => ' xī', + '徱' => ' piào', + '得' => ' dé', + '徾' => ' méi', + '忈' => ' rén', + '忇' => ' lè', + '忆' => ' yì', + '必' => ' bì', + '忄' => ' xin', + '心' => ' xīn', + '忂' => ' qú', + '忁' => ' bào', + '忀' => ' xiāng', + '徿' => ' lòng', + '徽' => ' huī', + '徲' => ' tí', + '徼' => ' jiǎo', + '徻' => ' huì', + '徺' => ' jiǎo', + '徹' => ' chè', + '徸' => ' chōng', + '德' => ' dé', + '徶' => ' bié', + '徵' => ' zhēng', + '徴' => ' zhēng', + '徳' => ' dé', + '徘' => ' pái', + '徖' => ' cóng', + '忊' => ' dìng', + '彰' => ' zhāng', + '彺' => ' wáng', + '役' => ' yì', + '彸' => ' zhōng', + '彷' => ' fǎng', + '彶' => ' jí', + '彵' => ' tuǒ', + '彴' => ' zhuó', + '彳' => ' chì', + '彲' => ' chī', + '影' => ' yǐng', + '彯' => ' piǎo', + '彼' => ' bǐ', + '彮' => ' yǒng', + '彭' => ' péng', + '彬' => ' bīn', + '彫' => ' diāo', + '彪' => ' biāo', + '彩' => ' cǎi', + '彨' => ' chī', + '彧' => ' yù', + '彦' => ' yàn', + '彥' => ' yàn', + '彻' => ' chè', + '彽' => ' dī', + '徕' => ' lái', + '徊' => ' huái', + '徔' => ' zhi', + '従' => ' cóng', + '徒' => ' tú', + '徑' => ' jìng', + '徐' => ' xú', + '徏' => ' zhì', + '徎' => ' chěng', + '徍' => ' wǎng', + '後' => ' hòu', + '律' => ' lǜ', + '徉' => ' yáng', + '彾' => ' líng', + '很' => ' hěn', + '徇' => ' xùn', + '徆' => ' xī', + '待' => ' dài', + '径' => ' jìng', + '徃' => ' wǎng', + '徂' => ' cú', + '征' => ' zhēng', + '往' => ' wǎng', + '彿' => ' fú', + '忉' => ' dāo', + '忋' => ' gǎi', + '彣' => ' wén', + '怌' => ' pēi', + '怖' => ' bù', + '怕' => ' pà', + '怔' => ' zhēng', + '怓' => ' náo', + '怒' => ' nù', + '怑' => ' bàn', + '怐' => ' jù', + '怏' => ' yàng', + '怎' => ' zěn', + '怍' => ' zuò', + '怋' => ' mín', + '怘' => ' hù', + '怊' => ' chāo', + '怉' => ' bǎo', + '怈' => ' yì', + '怇' => ' jù', + '怆' => ' chuàng', + '怅' => ' chàng', + '怄' => ' òu', + '怃' => ' wǔ', + '怂' => ' sǒng', + '态' => ' tài', + '怗' => ' tiē', + '怙' => ' hù', + '忿' => ' fèn', + '怦' => ' pēng', + '怰' => ' xuàn', + '怯' => ' qiè', + '怮' => ' yōu', + '怭' => ' bì', + '怬' => ' xì', + '怫' => ' fú', + '怪' => ' guài', + '怩' => ' ní', + '怨' => ' yuàn', + '性' => ' xìng', + '急' => ' jí', + '怚' => ' jù', + '怤' => ' fū', + '怣' => ' yóu', + '怢' => ' tū', + '怡' => ' yí', + '怠' => ' dài', + '怟' => ' dì', + '怞' => ' chóu', + '思' => ' sī', + '怜' => ' lián', + '怛' => ' dá', + '怀' => ' huái', + '忾' => ' kài', + '忌' => ' jì', + '忘' => ' wàng', + '忢' => ' wù', + '忡' => ' chōng', + '忠' => ' zhōng', + '忟' => ' wěn', + '忞' => ' mín', + '忝' => ' tiǎn', + '応' => ' yīng', + '忛' => ' fán', + '忚' => ' xī', + '忙' => ' máng', + '志' => ' zhì', + '忤' => ' wǔ', + '忖' => ' cǔn', + '忕' => ' shì', + '忔' => ' qì', + '忓' => ' gān', + '忒' => ' tè', + '忑' => ' tè', + '忐' => ' tǎn', + '忏' => ' chàn', + '忎' => ' rén', + '忍' => ' rěn', + '忣' => ' jí', + '忥' => ' xì', + '忽' => ' hū', + '忲' => ' tài', + '忼' => ' kāng', + '忻' => ' xīn', + '忺' => ' xiān', + '忹' => ' kuáng', + '忸' => ' niǔ', + '忷' => ' xiōng', + '忶' => ' hún', + '念' => ' niàn', + '忴' => ' qián', + '忳' => ' tún', + '忱' => ' chén', + '忦' => ' jiá', + '忰' => ' cuì', + '忯' => ' qí', + '忮' => ' zhì', + '忭' => ' biàn', + '忬' => ' yù', + '快' => ' kuài', + '忪' => ' sōng', + '忩' => ' cōng', + '忨' => ' wàn', + '忧' => ' yōu', + '彤' => ' tóng', + '形' => ' xíng', + '怲' => ' bǐng', + '廔' => ' lóu', + '廞' => ' xīn', + '廝' => ' sī', + '廜' => ' tú', + '廛' => ' chán', + '廚' => ' chú', + '廙' => ' yì', + '廘' => ' lù', + '廗' => ' dài', + '廖' => ' liào', + '廕' => ' yìn', + '廓' => ' kuò', + '廠' => ' chǎng', + '廒' => ' áo', + '廑' => ' jǐn', + '廐' => ' jiù', + '廏' => ' jiù', + '廎' => ' qǐng', + '廍' => ' pǒu', + '廌' => ' zhì', + '廋' => ' sōu', + '廊' => ' láng', + '廉' => ' lián', + '廟' => ' miào', + '廡' => ' wǔ', + '廇' => ' liù', + '廮' => ' yǐng', + '廸' => ' dí', + '廷' => ' tíng', + '延' => ' yán', + '廵' => ' xún', + '廴' => ' yǐn', + '廳' => ' tīng', + '廲' => ' lí', + '廱' => ' yōng', + '廰' => ' tīng', + '廯' => ' xiān', + '廭' => ' ji', + '廢' => ' fèi', + '廬' => ' lú', + '廫' => ' liáo', + '廪' => ' lǐn', + '廩' => ' lǐn', + '廨' => ' xiè', + '廧' => ' qiáng', + '廦' => ' bì', + '廥' => ' kuài', + '廤' => ' kù', + '廣' => ' guǎng', + '廈' => ' shà', + '廆' => ' guī', + '建' => ' jiàn', + '庠' => ' xiáng', + '庪' => ' guǐ', + '庩' => ' tú', + '庨' => ' xiāo', + '座' => ' zuò', + '度' => ' dù', + '庥' => ' xiū', + '庤' => ' zhì', + '庣' => ' tiāo', + '庢' => ' zhì', + '庡' => ' yǐ', + '废' => ' fèi', + '庬' => ' máng', + '庞' => ' páng', + '庝' => ' tóng', + '府' => ' fǔ', + '庛' => ' cì', + '庚' => ' gēng', + '庙' => ' miào', + '庘' => ' yā', + '店' => ' diàn', + '庖' => ' páo', + '底' => ' dǐ', + '庫' => ' kù', + '庭' => ' tíng', + '廅' => ' è', + '庺' => ' sōng', + '廄' => ' jiù', + '廃' => ' fèi', + '廂' => ' xiāng', + '廁' => ' cè', + '廀' => ' sōu', + '庿' => ' miào', + '庾' => ' yǔ', + '庽' => ' yù', + '庼' => ' qǐng', + '庻' => ' shù', + '庹' => ' tuǒ', + '庮' => ' yǒu', + '庸' => ' yōng', + '康' => ' kāng', + '庶' => ' shù', + '庵' => ' ān', + '庴' => ' jí', + '庳' => ' bì', + '庲' => ' lái', + '庱' => ' chěng', + '庰' => ' bìng', + '庯' => ' bū', + '廹' => ' pǎi', + '廻' => ' huí', + '彡' => ' shān', + '弼' => ' bì', + '彆' => ' biè', + '彅' => ' jian', + '彄' => ' kōu', + '彃' => ' bì', + '彂' => ' fā', + '彁' => ' ge', + '彀' => ' gòu', + '弿' => ' jiǎn', + '弾' => ' dàn', + '弽' => ' shè', + '弻' => ' bì', + '彈' => ' dàn', + '强' => ' qiáng', + '弹' => ' dàn', + '弸' => ' péng', + '強' => ' qiáng', + '弶' => ' jiàng', + '張' => ' zhāng', + '弴' => ' diāo', + '弳' => ' jìng', + '弲' => ' xuān', + '弱' => ' ruò', + '彇' => ' xiāo', + '彉' => ' guō', + '弯' => ' wān', + '彖' => ' tuàn', + '彠' => ' yuē', + '彟' => ' yuē', + '彞' => ' yí', + '彝' => ' yí', + '彜' => ' yí', + '彛' => ' yí', + '彚' => ' huì', + '彙' => ' huì', + '彘' => ' zhì', + '彗' => ' huì', + '录' => ' lù', + '彊' => ' jiàng', + '彔' => ' lù', + '当' => ' dāng', + '归' => ' guī', + '彑' => ' jì', + '彐' => ' jì', + '彏' => ' jué', + '彎' => ' wān', + '彍' => ' guō', + '彌' => ' mí', + '彋' => ' hóng', + '弰' => ' shāo', + '弮' => ' quān', + '廼' => ' nǎi', + '弈' => ' yì', + '弒' => ' shì', + '弑' => ' shì', + '弐' => ' èr', + '式' => ' shì', + '弎' => ' sān', + '弍' => ' èr', + '弌' => ' yī', + '弋' => ' yì', + '弊' => ' bì', + '弉' => ' zàng', + '弇' => ' yǎn', + '弔' => ' diào', + '弆' => ' jǔ', + '弅' => ' fèn', + '弄' => ' nòng', + '弃' => ' qì', + '异' => ' yì', + '弁' => ' biàn', + '开' => ' kāi', + '廿' => ' niàn', + '廾' => ' gǒng', + '廽' => ' huí', + '弓' => ' gōng', + '引' => ' yǐn', + '弭' => ' mǐ', + '弢' => ' tāo', + '弬' => ' yí', + '弫' => ' zhěn', + '弪' => ' jìng', + '弩' => ' nǔ', + '弨' => ' chāo', + '弧' => ' hú', + '弦' => ' xián', + '弥' => ' mí', + '弤' => ' dǐ', + '弣' => ' fǔ', + '弡' => ' jué', + '弖' => ' hù', + '张' => ' zhāng', + '弟' => ' dì', + '弞' => ' shěn', + '弝' => ' bà', + '弜' => ' jiàng', + '弛' => ' chí', + '弚' => ' tuí', + '弙' => ' wū', + '弘' => ' hóng', + '弗' => ' fú', + '怱' => ' cōng', + '怳' => ' huǎng', + '懒' => ' lǎn', + '慅' => ' sāo', + '慏' => ' mǐng', + '慎' => ' shèn', + '慍' => ' yùn', + '慌' => ' huāng', + '態' => ' tài', + '慊' => ' qiàn', + '慉' => ' xù', + '慈' => ' cí', + '慇' => ' yīn', + '慆' => ' tāo', + '慄' => ' lì', + '慑' => ' shè', + '慃' => ' yǎng', + '慂' => ' yǒng', + '慁' => ' hùn', + '慀' => ' xì', + '愿' => ' yuàn', + '愾' => ' kài', + '愽' => ' bó', + '愼' => ' shèn', + '愻' => ' xùn', + '愺' => ' cǎo', + '慐' => ' gong', + '慒' => ' cóng', + '愸' => ' zhěng', + '慟' => ' tòng', + '慩' => ' lián', + '慨' => ' kǎi', + '慧' => ' huì', + '慦' => ' jiù', + '慥' => ' zào', + '慤' => ' què', + '慣' => ' guàn', + '慢' => ' màn', + '慡' => ' shuǎng', + '慠' => ' ào', + '慞' => ' zhāng', + '慓' => ' piāo', + '慝' => ' tè', + '慜' => ' mǐn', + '慛' => ' cuī', + '慚' => ' cán', + '慙' => ' cán', + '慘' => ' cǎn', + '慗' => ' chì', + '慖' => ' guó', + '慕' => ' mù', + '慔' => ' mù', + '愹' => ' yǒng', + '愷' => ' kǎi', + '慫' => ' sǒng', + '愑' => ' yǒng', + '愛' => ' ài', + '愚' => ' yú', + '愙' => ' kè', + '愘' => ' qià', + '愗' => ' mào', + '愖' => ' chén', + '愕' => ' è', + '愔' => ' yīn', + '愓' => ' dàng', + '愒' => ' kài', + '愐' => ' miǎn', + '愝' => ' yǎn', + '意' => ' yì', + '愎' => ' bì', + '愍' => ' mǐn', + '愌' => ' huàn', + '愋' => ' xuān', + '愊' => ' bì', + '愉' => ' yú', + '愈' => ' yù', + '愇' => ' wěi', + '愆' => ' qiān', + '愜' => ' qiè', + '愞' => ' nuò', + '愶' => ' xié', + '愫' => ' sù', + '愵' => ' nì', + '愴' => ' chuàng', + '愳' => ' jù', + '愲' => ' gǔ', + '愱' => ' jí', + '愰' => ' huàng', + '愯' => ' sǒng', + '愮' => ' yáo', + '愭' => ' qí', + '愬' => ' sù', + '愪' => ' yún', + '感' => ' gǎn', + '愩' => ' gōng', + '愨' => ' què', + '愧' => ' kuì', + '愦' => ' kuì', + '愥' => ' ying', + '愤' => ' fèn', + '愣' => ' lèng', + '愢' => ' sāi', + '愡' => ' zǒng', + '愠' => ' yùn', + '慪' => ' òu', + '慬' => ' qín', + '愄' => ' wēi', + '憭' => ' liǎo', + '憷' => ' chù', + '憶' => ' yì', + '憵' => ' pī', + '憴' => ' shéng', + '憳' => ' tǎn', + '憲' => ' xiàn', + '憱' => ' cù', + '憰' => ' jué', + '憯' => ' cǎn', + '憮' => ' wǔ', + '憬' => ' jǐng', + '憹' => ' náo', + '憫' => ' mǐn', + '憪' => ' xián', + '憩' => ' qì', + '憨' => ' hān', + '憧' => ' chōng', + '憦' => ' lào', + '憥' => ' láo', + '憤' => ' fèn', + '憣' => ' fān', + '憢' => ' xiāo', + '憸' => ' xiān', + '憺' => ' dàn', + '憠' => ' jué', + '懇' => ' kěn', + '懑' => ' mèn', + '懐' => ' huái', + '懏' => ' jùn', + '懎' => ' sè', + '懍' => ' lǐn', + '懌' => ' yì', + '懋' => ' mào', + '懊' => ' ào', + '應' => ' yīng', + '懈' => ' xiè', + '懆' => ' cǎo', + '憻' => ' tǎn', + '懅' => ' jù', + '懄' => ' qín', + '懃' => ' qín', + '懂' => ' dǒng', + '懁' => ' xuān', + '懀' => ' wèi', + '憿' => ' jiǎo', + '憾' => ' hàn', + '憽' => ' sōng', + '憼' => ' jǐng', + '憡' => ' cè', + '憟' => ' sù', + '慭' => ' yìn', + '慹' => ' zhí', + '憃' => ' chōng', + '憂' => ' yōu', + '憁' => ' còng', + '憀' => ' liáo', + '慿' => ' píng', + '慾' => ' yù', + '慽' => ' qī', + '慼' => ' qī', + '慻' => ' juàn', + '慺' => ' lóu', + '慸' => ' dì', + '憅' => ' tòng', + '慷' => ' kāng', + '慶' => ' qìng', + '慵' => ' yōng', + '慴' => ' shè', + '慳' => ' qiān', + '慲' => ' mán', + '慱' => ' tuán', + '慰' => ' wèi', + '慯' => ' shāng', + '慮' => ' lǜ', + '憄' => ' zhì', + '憆' => ' chēng', + '憞' => ' duì', + '憓' => ' huì', + '憝' => ' duì', + '憜' => ' duǒ', + '憛' => ' tán', + '憚' => ' dàn', + '憙' => ' xī', + '憘' => ' xǐ', + '憗' => ' yìn', + '憖' => ' yìn', + '憕' => ' chéng', + '憔' => ' qiáo', + '憒' => ' kuì', + '憇' => ' qì', + '憑' => ' píng', + '憐' => ' lián', + '憏' => ' chì', + '憎' => ' zēng', + '憍' => ' jiāo', + '憌' => ' qióng', + '憋' => ' biē', + '憊' => ' bèi', + '憉' => ' péng', + '憈' => ' qū', + '愅' => ' gé', + '愃' => ' xuān', + '怴' => ' xù', + '恴' => ' dé', + '恾' => ' máng', + '恽' => ' yùn', + '恼' => ' nǎo', + '恻' => ' cè', + '恺' => ' kǎi', + '恹' => ' yān', + '恸' => ' tòng', + '恷' => ' xiao', + '恶' => ' è', + '恵' => ' huì', + '恳' => ' kěn', + '悀' => ' yǒng', + '恲' => ' pēng', + '恱' => ' yuè', + '恰' => ' qià', + '息' => ' xī', + '恮' => ' quān', + '恭' => ' gōng', + '恬' => ' tián', + '恫' => ' dòng', + '恪' => ' kè', + '恩' => ' ēn', + '恿' => ' yǒng', + '悁' => ' yuān', + '恧' => ' nǜ', + '悎' => ' hào', + '悘' => ' yī', + '悗' => ' mán', + '悖' => ' bèi', + '悕' => ' xī', + '悔' => ' huǐ', + '悓' => ' qiàn', + '悒' => ' yì', + '悑' => ' bù', + '悐' => ' tì', + '悏' => ' qiè', + '悍' => ' hàn', + '悂' => ' pī', + '悌' => ' tì', + '悋' => ' lìn', + '悊' => ' zhé', + '悉' => ' xī', + '悈' => ' jiè', + '悇' => ' tú', + '悆' => ' yù', + '悅' => ' yuè', + '悄' => ' qiāo', + '悃' => ' kǔn', + '恨' => ' hèn', + '恦' => ' shàng', + '悚' => ' sǒng', + '恀' => ' shì', + '恊' => ' xié', + '恉' => ' zhǐ', + '恈' => ' móu', + '恇' => ' kuāng', + '恆' => ' héng', + '恅' => ' lǎo', + '恄' => ' xì', + '恃' => ' shì', + '恂' => ' xún', + '恁' => ' nèn', + '怿' => ' yì', + '恌' => ' tiāo', + '怾' => ' zhǐ', + '怽' => ' mo', + '怼' => ' duì', + '总' => ' zǒng', + '怺' => ' yong', + '怹' => ' tān', + '怸' => ' xī', + '怷' => ' shù', + '怶' => ' bì', + '怵' => ' chù', + '恋' => ' liàn', + '恍' => ' huǎng', + '恥' => ' chǐ', + '恚' => ' huì', + '恤' => ' xù', + '恣' => ' zì', + '恢' => ' huī', + '恡' => ' lìn', + '恠' => ' guài', + '恟' => ' xiōng', + '恞' => ' yí', + '恝' => ' jiá', + '恜' => ' chì', + '恛' => ' huí', + '恙' => ' yàng', + '恎' => ' dié', + '恘' => ' qiū', + '恗' => ' hū', + '恖' => ' si', + '恕' => ' shù', + '恔' => ' jiǎo', + '恓' => ' xī', + '恒' => ' héng', + '恑' => ' guǐ', + '恐' => ' kǒng', + '恏' => ' hào', + '悙' => ' hēng', + '悛' => ' quān', + '愂' => ' bèi', + '惝' => ' chǎng', + '惧' => ' jù', + '惦' => ' diàn', + '惥' => ' yǒng', + '惤' => ' jiān', + '惣' => ' zǒng', + '惢' => ' suǒ', + '惡' => ' è', + '惠' => ' huì', + '惟' => ' wéi', + '惞' => ' xīn', + '惜' => ' xī', + '惩' => ' chéng', + '惛' => ' hūn', + '惚' => ' hū', + '惙' => ' chuò', + '惘' => ' wǎng', + '惗' => ' niè', + '惖' => ' tì', + '惕' => ' tì', + '惔' => ' tán', + '惓' => ' quán', + '惒' => ' hé', + '惨' => ' cǎn', + '惪' => ' dé', + '惐' => ' yù', + '惷' => ' chǔn', + '愁' => ' chóu', + '愀' => ' qiǎo', + '惿' => ' tí', + '惾' => ' zōng', + '惽' => ' mǐn', + '惼' => ' biǎn', + '惻' => ' cè', + '惺' => ' xīng', + '惹' => ' rě', + '惸' => ' qióng', + '惶' => ' huáng', + '惫' => ' bèi', + '惵' => ' dié', + '惴' => ' zhuì', + '想' => ' xiǎng', + '惲' => ' yùn', + '惱' => ' nǎo', + '惰' => ' duò', + '惯' => ' guàn', + '惮' => ' dàn', + '惭' => ' cán', + '惬' => ' qiè', + '惑' => ' huò', + '惏' => ' lán', + '悜' => ' chěng', + '您' => ' nín', + '悲' => ' bēi', + '悱' => ' fěi', + '悰' => ' cóng', + '悯' => ' mǐn', + '悮' => ' wù', + '悭' => ' qiān', + '悬' => ' xuán', + '悫' => ' què', + '悪' => ' è', + '悩' => ' nǎo', + '悧' => ' lì', + '悴' => ' cuì', + '悦' => ' yuè', + '悥' => ' yì', + '悤' => ' cōng', + '患' => ' huàn', + '悢' => ' liàng', + '悡' => ' lí', + '悠' => ' yōu', + '悟' => ' wù', + '悞' => ' wù', + '悝' => ' kuī', + '悳' => ' duó', + '悵' => ' chàng', + '惎' => ' jì', + '惃' => ' gǔn', + '惍' => ' jīn', + '惌' => ' yuān', + '惋' => ' wǎn', + '惊' => ' jīng', + '惉' => ' zhān', + '惈' => ' guǒ', + '惇' => ' dūn', + '惆' => ' chóu', + '情' => ' qíng', + '惄' => ' nì', + '惂' => ' kǎn', + '悶' => ' mèn', + '惁' => ' xī', + '惀' => ' lún', + '悿' => ' tiǎn', + '悾' => ' kōng', + '悽' => ' qī', + '悼' => ' dào', + '悻' => ' xìng', + '悺' => ' guàn', + '悹' => ' guàn', + '悸' => ' jì', + '悷' => ' sàn', + '攓' => ' qiān', + '攕' => ' xiān', + '库' => ' kù', + '楪' => ' yè', + '楴' => ' tì', + '楳' => ' méi', + '楲' => ' wēi', + '楱' => ' zòu', + '楰' => ' yú', + '楯' => ' dùn', + '楮' => ' chǔ', + '業' => ' yè', + '楬' => ' jié', + '楫' => ' jí', + '楩' => ' pián', + '楶' => ' jié', + '楨' => ' zhēn', + '楧' => ' yǎng', + '楦' => ' xuàn', + '楥' => ' xuàn', + '楤' => ' sǒng', + '楣' => ' méi', + '楢' => ' yóu', + '楡' => ' yú', + '楠' => ' nán', + '楟' => ' tíng', + '極' => ' jí', + '楷' => ' kǎi', + '楝' => ' liàn', + '榄' => ' lǎn', + '榎' => ' jiǎ', + '榍' => ' xiè', + '榌' => ' pi', + '榋' => ' chu', + '榊' => ' shen', + '榉' => ' jǔ', + '榈' => ' lǘ', + '榇' => ' chèn', + '榆' => ' yú', + '榅' => ' wēn', + '榃' => ' tán', + '楸' => ' qiū', + '概' => ' gài', + '榁' => ' shi', + '榀' => ' pǐn', + '楿' => ' xiang', + '楾' => ' quan', + '楽' => ' lè', + '楼' => ' lóu', + '楻' => ' huáng', + '楺' => ' rǒu', + '楹' => ' yíng', + '楞' => ' léng', + '楜' => ' hú', + '榐' => ' zhǎn', + '椶' => ' zōng', + '楀' => ' yǔ', + '椿' => ' chūn', + '椾' => ' jiān', + '椽' => ' chuán', + '椼' => ' yǎn', + '椻' => ' yàn', + '椺' => ' xí', + '椹' => ' shèn', + '椸' => ' yí', + '椷' => ' jiān', + '椵' => ' jiǎ', + '楂' => ' zhā', + '椴' => ' duàn', + '椳' => ' wēi', + '椲' => ' wěi', + '椱' => ' fù', + '椰' => ' yē', + '椯' => ' duǒ', + '椮' => ' sēn', + '椭' => ' tuǒ', + '椬' => ' yi', + '椫' => ' zhǎn', + '楁' => ' hé', + '楃' => ' wò', + '楛' => ' hù', + '楐' => ' jiè', + '楚' => ' chǔ', + '楙' => ' mào', + '楘' => ' mù', + '楗' => ' jiàn', + '楖' => ' zhì', + '楕' => ' tuǒ', + '楔' => ' xiē', + '楓' => ' fēng', + '楒' => ' sī', + '楑' => ' kuí', + '楏' => ' kuí', + '楄' => ' pián', + '楎' => ' huī', + '楍' => ' běn', + '楌' => ' yán', + '楋' => ' là', + '楊' => ' yáng', + '楉' => ' ruò', + '楈' => ' xū', + '楇' => ' huò', + '楆' => ' yāo', + '楅' => ' bī', + '榏' => ' yì', + '榑' => ' fú', + '椩' => ' geng', + '槒' => ' xù', + '槜' => ' zuì', + '槛' => ' kǎn', + '槚' => ' jiǎ', + '槙' => ' diān', + '様' => ' yàng', + '槗' => ' qiao', + '槖' => ' tuó', + '槕' => ' zhuó', + '槔' => ' gāo', + '槓' => ' gàng', + '槑' => ' méi', + '槞' => ' long', + '槐' => ' huái', + '槏' => ' qiǎn', + '槎' => ' chá', + '槍' => ' qiāng', + '槌' => ' chuí', + '構' => ' gòu', + '槊' => ' shuò', + '槉' => ' jí', + '槈' => ' nòu', + '槇' => ' diān', + '槝' => ' dao', + '槟' => ' bīn', + '槅' => ' gé', + '槬' => ' huà', + '槶' => ' guì', + '槵' => ' huàn', + '槴' => ' hù', + '槳' => ' jiǎng', + '槲' => ' hú', + '槱' => ' yǒu', + '槰' => ' péng', + '槯' => ' cuī', + '槮' => ' sēn', + '槭' => ' qī', + '槫' => ' tuán', + '槠' => ' zhū', + '槪' => ' gài', + '槩' => ' gài', + '槨' => ' guǒ', + '槧' => ' qiàn', + '槦' => ' yōng', + '槥' => ' huì', + '槤' => ' lián', + '槣' => ' jī', + '槢' => ' xí', + '槡' => ' sang', + '槆' => ' xún', + '槄' => ' tāo', + '榒' => ' nuò', + '榞' => ' yuán', + '榨' => ' zhà', + '榧' => ' fěi', + '榦' => ' gàn', + '榥' => ' huàng', + '榤' => ' jié', + '榣' => ' yáo', + '榢' => ' jià', + '榡' => ' sù', + '榠' => ' míng', + '榟' => ' zǐ', + '榝' => ' shā', + '榪' => ' mà', + '榜' => ' bǎng', + '榛' => ' zhēn', + '榚' => ' yǎo', + '榙' => ' tā', + '榘' => ' jǔ', + '榗' => ' jiàn', + '榖' => ' gǔ', + '榕' => ' róng', + '榔' => ' láng', + '榓' => ' mì', + '榩' => ' qián', + '榫' => ' sǔn', + '槃' => ' pán', + '榸' => ' zhāi', + '槂' => ' sūn', + '槁' => ' gǎo', + '槀' => ' gǎo', + '榿' => ' qī', + '榾' => ' gǔ', + '榽' => ' xī', + '榼' => ' kē', + '榻' => ' tà', + '榺' => ' shèng', + '榹' => ' sī', + '榷' => ' què', + '榬' => ' yuán', + '榶' => ' táng', + '榵' => ' róng', + '榴' => ' liú', + '榳' => ' tíng', + '榲' => ' yún', + '榱' => ' cuī', + '榰' => ' zhī', + '榯' => ' shí', + '榮' => ' róng', + '榭' => ' xiè', + '椪' => ' pèng', + '椨' => ' fu', + '槸' => ' yì', + '梚' => ' wǎn', + '梤' => ' fén', + '梣' => ' cén', + '梢' => ' shāo', + '梡' => ' hún', + '梠' => ' lǚ', + '梟' => ' xiāo', + '梞' => ' jì', + '條' => ' tiáo', + '梜' => ' jiā', + '梛' => ' nuó', + '梙' => ' huàn', + '梦' => ' mèng', + '梘' => ' jiǎn', + '梗' => ' gěng', + '梖' => ' bèi', + '梕' => ' rèn', + '梔' => ' zhī', + '梓' => ' zǐ', + '梒' => ' hán', + '梑' => ' dí', + '梐' => ' bì', + '梏' => ' gù', + '梥' => ' sōng', + '梧' => ' wú', + '梍' => ' zào', + '梴' => ' chān', + '梾' => ' lái', + '梽' => ' zhì', + '梼' => ' táo', + '梻' => ' fo', + '梺' => ' xia', + '梹' => ' bīn', + '梸' => ' lí', + '梷' => ' jìng', + '梶' => ' wěi', + '梵' => ' fàn', + '梳' => ' shū', + '梨' => ' lí', + '梲' => ' zhuó', + '梱' => ' kǔn', + '械' => ' xiè', + '梯' => ' tī', + '梮' => ' jū', + '梭' => ' suō', + '梬' => ' yǐng', + '梫' => ' qǐn', + '梪' => ' dòu', + '梩' => ' lí', + '梎' => ' āo', + '梌' => ' tú', + '检' => ' jiǎn', + '桦' => ' huà', + '桰' => ' kuò', + '桯' => ' tīng', + '桮' => ' bēi', + '桭' => ' zhēn', + '桬' => ' shā', + '桫' => ' suō', + '桪' => ' xún', + '桩' => ' zhuāng', + '桨' => ' jiǎng', + '桧' => ' guì', + '桥' => ' qiáo', + '桲' => ' po', + '桤' => ' qī', + '档' => ' dàng', + '桢' => ' zhēn', + '桡' => ' ráo', + '桠' => ' yā', + '桟' => ' zhàn', + '桞' => ' liu', + '桝' => ' jie', + '桜' => ' yīng', + '桚' => ' zǎn', + '桱' => ' jìng', + '桳' => ' bèn', + '梋' => ' xuān', + '梀' => ' sù', + '梊' => ' dì', + '梉' => ' zhuāng', + '梈' => ' pēng', + '梇' => ' lòng', + '梆' => ' bāng', + '梅' => ' méi', + '梄' => ' yǒu', + '梃' => ' tǐng', + '梂' => ' qiú', + '梁' => ' liáng', + '桿' => ' gǎn', + '桴' => ' fú', + '桾' => ' jūn', + '桽' => ' wěn', + '桼' => ' qī', + '桻' => ' fēng', + '桺' => ' liǔ', + '桹' => ' láng', + '桸' => ' xī', + '桷' => ' jué', + '桶' => ' tǒng', + '桵' => ' ruí', + '梿' => ' lián', + '棁' => ' zhuō', + '椧' => ' mìng', + '椂' => ' lù', + '椌' => ' qiāng', + '椋' => ' liáng', + '椊' => ' zuó', + '椉' => ' chéng', + '椈' => ' jú', + '椇' => ' jǔ', + '椆' => ' chóu', + '椅' => ' yǐ', + '椄' => ' jiē', + '椃' => ' háo', + '椁' => ' guǒ', + '椎' => ' chuí', + '椀' => ' wǎn', + '棿' => ' ní', + '棾' => ' qíng', + '棽' => ' shēn', + '棼' => ' fén', + '棻' => ' fēn', + '棺' => ' guān', + '棹' => ' zhào', + '棸' => ' zōu', + '棷' => ' zōu', + '植' => ' zhí', + '椏' => ' yā', + '棵' => ' kē', + '検' => ' jiǎn', + '椦' => ' quan', + '椥' => ' zhī', + '椤' => ' luó', + '椣' => ' dian', + '椢' => ' guì', + '椡' => ' dao', + '椠' => ' qiàn', + '椟' => ' dú', + '椞' => ' xì', + '椝' => ' guī', + '椛' => ' hua', + '椐' => ' jū', + '椚' => ' men', + '椙' => ' chang', + '椘' => ' chǔ', + '椗' => ' dìng', + '椖' => ' péng', + '椕' => ' bīn', + '椔' => ' zī', + '椓' => ' zhuó', + '椒' => ' jiāo', + '椑' => ' bēi', + '棶' => ' lái', + '棴' => ' fú', + '棂' => ' líng', + '棎' => ' chán', + '棘' => ' jí', + '棗' => ' zǎo', + '棖' => ' chéng', + '棕' => ' zōng', + '棔' => ' hūn', + '棓' => ' bàng', + '棒' => ' bàng', + '棑' => ' pái', + '棐' => ' fěi', + '棏' => ' dé', + '棍' => ' gùn', + '棚' => ' péng', + '棌' => ' cài', + '棋' => ' qí', + '棊' => ' qí', + '棉' => ' mián', + '棈' => ' qiàn', + '棇' => ' cōng', + '棆' => ' lún', + '棅' => ' bìng', + '棄' => ' qì', + '棃' => ' lí', + '棙' => ' lì', + '棛' => ' yù', + '棳' => ' zhuō', + '棨' => ' qǐ', + '棲' => ' qī', + '棱' => ' léng', + '棰' => ' chuí', + '棯' => ' rěn', + '森' => ' sēn', + '棭' => ' yì', + '棬' => ' quān', + '棫' => ' yù', + '棪' => ' yǎn', + '棩' => ' yuān', + '棧' => ' zhàn', + '棜' => ' yù', + '棦' => ' chēng', + '棥' => ' fán', + '棤' => ' cuò', + '棣' => ' dì', + '棢' => ' wǎng', + '棡' => ' gāng', + '棠' => ' táng', + '棟' => ' dòng', + '棞' => ' jùn', + '棝' => ' gù', + '槷' => ' niè', + '槹' => ' gāo', + '桘' => ' zhuì', + '欋' => ' qú', + '欕' => ' yan', + '欔' => ' jué', + '欓' => ' dǎng', + '欒' => ' luán', + '欑' => ' cuán', + '欐' => ' lì', + '欏' => ' luó', + '欎' => ' yù', + '欍' => ' jiu', + '欌' => ' cang', + '權' => ' quán', + '欗' => ' lán', + '欉' => ' cóng', + '欈' => ' wéi', + '欇' => ' shè', + '欆' => ' shuāng', + '欅' => ' jǔ', + '欄' => ' lán', + '欃' => ' chán', + '欂' => ' bó', + '欁' => ' nóng', + '欀' => ' xiāng', + '欖' => ' lǎn', + '欘' => ' zhú', + '櫾' => ' yóu', + '欥' => ' yì', + '欯' => ' xì', + '欮' => ' jué', + '欭' => ' yì', + '欬' => ' kài', + '欫' => ' qì', + '欪' => ' chù', + '欩' => ' chāo', + '欨' => ' xū', + '欧' => ' ōu', + '欦' => ' qiān', + '欤' => ' yú', + '欙' => ' léi', + '欣' => ' xīn', + '欢' => ' huān', + '次' => ' cì', + '欠' => ' qiàn', + '欟' => ' guang', + '欞' => ' líng', + '欝' => ' yù', + '欜' => ' náng', + '欛' => ' bà', + '欚' => ' lǐ', + '櫿' => ' yíng', + '櫽' => ' yǐn', + '欱' => ' hē', + '櫗' => ' miè', + '櫡' => ' zhuó', + '櫠' => ' fèi', + '櫟' => ' lì', + '櫞' => ' yuán', + '櫝' => ' dú', + '櫜' => ' gāo', + '櫛' => ' zhì', + '櫚' => ' lú', + '櫙' => ' ōu', + '櫘' => ' huì', + '櫖' => ' lǜ', + '櫣' => ' lián', + '櫕' => ' cuán', + '櫔' => ' lì', + '櫓' => ' lǔ', + '櫒' => ' sà', + '櫑' => ' léi', + '櫐' => ' lěi', + '櫏' => ' qiān', + '櫎' => ' huǎng', + '櫍' => ' zhì', + '櫌' => ' yōu', + '櫢' => ' sǒu', + '櫤' => ' jiang', + '櫼' => ' jiān', + '櫱' => ' niè', + '櫻' => ' yīng', + '櫺' => ' líng', + '櫹' => ' xiāo', + '櫸' => ' jǔ', + '櫷' => ' guī', + '櫶' => ' xiǎn', + '櫵' => ' jiao', + '櫴' => ' lài', + '櫳' => ' lóng', + '櫲' => ' yù', + '櫰' => ' huái', + '櫥' => ' chú', + '櫯' => ' sū', + '櫮' => ' è', + '櫭' => ' jié', + '櫬' => ' chèn', + '櫫' => ' zhū', + '櫪' => ' lì', + '櫩' => ' yán', + '櫨' => ' lú', + '櫧' => ' zhū', + '櫦' => ' qing', + '欰' => ' xù', + '欲' => ' yù', + '櫊' => ' ge', + '歳' => ' suì', + '歽' => ' zhé', + '歼' => ' jiān', + '死' => ' sǐ', + '歺' => ' è', + '歹' => ' dǎi', + '歸' => ' guī', + '歷' => ' lì', + '歶' => ' yú', + '歵' => ' cuò', + '歴' => ' lì', + '歲' => ' suì', + '歿' => ' mò', + '歱' => ' zhǒng', + '歰' => ' sè', + '歯' => ' chǐ', + '歮' => ' sè', + '歭' => ' chí', + '歬' => ' qián', + '歫' => ' jù', + '歪' => ' wāi', + '歩' => ' bù', + '歨' => ' bù', + '歾' => ' mò', + '殀' => ' yāo', + '武' => ' wǔ', + '殍' => ' piǎo', + '殗' => ' yè', + '殖' => ' zhí', + '殕' => ' fǒu', + '殔' => ' yì', + '殓' => ' liàn', + '殒' => ' yǔn', + '殑' => ' qíng', + '殐' => ' sù', + '殏' => ' qiú', + '殎' => ' qià', + '殌' => ' jué', + '殁' => ' mò', + '残' => ' cán', + '殊' => ' shū', + '殉' => ' xùn', + '殈' => ' xù', + '殇' => ' shāng', + '殆' => ' dài', + '殅' => ' shēng', + '殄' => ' tiǎn', + '殃' => ' yāng', + '殂' => ' cú', + '歧' => ' qí', + '步' => ' bù', + '欳' => ' kuì', + '欿' => ' kǎn', + '歉' => ' qiàn', + '歈' => ' yú', + '歇' => ' xiē', + '歆' => ' xīn', + '歅' => ' yīn', + '歄' => ' guā', + '歃' => ' shà', + '歂' => ' chuǎn', + '歁' => ' kǎn', + '歀' => ' kuǎn', + '款' => ' kuǎn', + '歋' => ' yè', + '欽' => ' qīn', + '欼' => ' chǐ', + '欻' => ' chuā', + '欺' => ' qī', + '欹' => ' yī', + '欸' => ' āi', + '欷' => ' xī', + '欶' => ' shuò', + '欵' => ' kuǎn', + '欴' => ' láng', + '歊' => ' xiāo', + '歌' => ' gē', + '此' => ' cǐ', + '歙' => ' shè', + '正' => ' zhèng', + '止' => ' zhǐ', + '歡' => ' huān', + '歠' => ' chuò', + '歟' => ' yú', + '歞' => ' è', + '歝' => ' yì', + '歜' => ' chù', + '歛' => ' hān', + '歚' => ' shàn', + '歘' => ' chuā', + '歍' => ' wū', + '歗' => ' xiào', + '歖' => ' xǐ', + '歕' => ' pēn', + '歔' => ' xū', + '歓' => ' huān', + '歒' => ' tì', + '歑' => ' hū', + '歐' => ' ōu', + '歏' => ' jìn', + '歎' => ' tàn', + '櫋' => ' mián', + '櫉' => ' chú', + '槺' => ' kāng', + '樺' => ' huà', + '橄' => ' gǎn', + '橃' => ' fá', + '橂' => ' diàn', + '橁' => ' chūn', + '橀' => ' xī', + '樿' => ' shàn', + '樾' => ' yuè', + '樽' => ' zūn', + '樼' => ' zhēn', + '樻' => ' kuì', + '樹' => ' shù', + '橆' => ' wǔ', + '樸' => ' pǔ', + '樷' => ' cóng', + '樶' => ' zuī', + '樵' => ' qiáo', + '樴' => ' zhí', + '樳' => ' xún', + '樲' => ' èr', + '樱' => ' yīng', + '樰' => ' xue', + '樯' => ' qiáng', + '橅' => ' mó', + '橇' => ' qiāo', + '樭' => ' ji', + '橔' => ' dūn', + '橞' => ' huì', + '橝' => ' diàn', + '橜' => ' jué', + '橛' => ' jué', + '橚' => ' sù', + '橙' => ' chéng', + '橘' => ' jú', + '橗' => ' méng', + '橖' => ' táng', + '橕' => ' chēng', + '橓' => ' shùn', + '橈' => ' ráo', + '橒' => ' yún', + '橑' => ' lǎo', + '橐' => ' tuó', + '橏' => ' zhǎn', + '橎' => ' fán', + '橍' => ' rùn', + '橌' => ' xiàn', + '橋' => ' qiáo', + '橊' => ' liú', + '橉' => ' lìn', + '樮' => ' yan', + '樬' => ' cōng', + '橠' => ' nuǒ', + '樆' => ' lí', + '樐' => ' lǔ', + '樏' => ' lěi', + '樎' => ' sù', + '樍' => ' zé', + '樌' => ' guàn', + '樋' => ' tǒng', + '樊' => ' fán', + '樉' => ' shuǎng', + '樈' => ' qíng', + '樇' => ' xiū', + '樅' => ' cōng', + '樒' => ' mì', + '樄' => ' chén', + '樃' => ' lǎng', + '樂' => ' lè', + '樁' => ' zhuāng', + '樀' => ' dī', + '槿' => ' jǐn', + '槾' => ' màn', + '槽' => ' cáo', + '槼' => ' guī', + '槻' => ' guī', + '樑' => ' liáng', + '樓' => ' lóu', + '樫' => ' jiān', + '樠' => ' mán', + '横' => ' héng', + '権' => ' quán', + '樨' => ' xī', + '樧' => ' shā', + '樦' => ' zhù', + '樥' => ' péng', + '樤' => ' tiáo', + '樣' => ' yàng', + '樢' => ' niǎo', + '模' => ' mó', + '樟' => ' zhāng', + '樔' => ' cháo', + '樞' => ' shū', + '樝' => ' zhā', + '樜' => ' zhè', + '樛' => ' jiū', + '樚' => ' lù', + '標' => ' biāo', + '樘' => ' táng', + '樗' => ' chū', + '樖' => ' kē', + '樕' => ' sù', + '機' => ' jī', + '橡' => ' xiàng', + '櫈' => ' dèng', + '檣' => ' qiáng', + '檭' => ' yín', + '檬' => ' méng', + '檫' => ' chá', + '檪' => ' li', + '檩' => ' lǐn', + '檨' => ' shē', + '檧' => ' sōng', + '檦' => ' biǎo', + '檥' => ' yǐ', + '檤' => ' dào', + '檢' => ' jiǎn', + '檯' => ' tái', + '檡' => ' zhái', + '檠' => ' qíng', + '檟' => ' jiǎ', + '檞' => ' jiě', + '檝' => ' jí', + '檜' => ' guì', + '檛' => ' zhuā', + '檚' => ' chǔ', + '檙' => ' chéng', + '檘' => ' píng', + '檮' => ' táo', + '檰' => ' mián', + '檖' => ' suì', + '檽' => ' nòu', + '櫇' => ' pó', + '櫆' => ' kuí', + '櫅' => ' jī', + '櫄' => ' chūn', + '櫃' => ' guì', + '櫂' => ' zhào', + '櫁' => ' mì', + '櫀' => ' qí', + '檿' => ' yǎn', + '檾' => ' qǐng', + '檼' => ' yìn', + '檱' => ' qí', + '檻' => ' kǎn', + '檺' => ' gǎo', + '檹' => ' yī', + '檸' => ' níng', + '檷' => ' nǐ', + '檶' => ' qiān', + '檵' => ' jì', + '檴' => ' huò', + '檳' => ' bīn', + '檲' => ' tuán', + '檗' => ' bò', + '檕' => ' jì', + '橢' => ' tuǒ', + '橮' => ' liǔ', + '橸' => ' jing', + '橷' => ' dōu', + '橶' => ' jí', + '橵' => ' san', + '橴' => ' zi', + '橳' => ' sheng', + '橲' => ' xi', + '橱' => ' chú', + '橰' => ' gāo', + '橯' => ' lào', + '橭' => ' gū', + '橺' => ' jian', + '橬' => ' qián', + '橫' => ' héng', + '橪' => ' rǎn', + '橩' => ' qióng', + '橨' => ' fén', + '橧' => ' zēng', + '橦' => ' tóng', + '橥' => ' zhū', + '橤' => ' ruǐ', + '橣' => ' nǐng', + '橹' => ' lǔ', + '橻' => ' chu', + '檔' => ' dàng', + '檉' => ' chēng', + '檓' => ' huǐ', + '檒' => ' fēng', + '檑' => ' léi', + '檐' => ' yán', + '檏' => ' pǔ', + '檎' => ' qín', + '檍' => ' yì', + '檌' => ' zuì', + '檋' => ' jú', + '檊' => ' gàn', + '檈' => ' xuán', + '橼' => ' yuán', + '檇' => ' zuì', + '檆' => ' shān', + '檅' => ' suì', + '檄' => ' xí', + '檃' => ' yǐn', + '檂' => ' nóng', + '檁' => ' lǐn', + '檀' => ' tán', + '橿' => ' jiāng', + '橾' => ' shū', + '橽' => ' tà', + '桙' => ' yú', + '桗' => ' duò', + '攖' => ' yīng', + '昨' => ' zuó', + '昲' => ' fèi', + '昱' => ' yù', + '昰' => ' shì', + '是' => ' shì', + '昮' => ' zòng', + '昭' => ' zhāo', + '昬' => ' hūn', + '昫' => ' xù', + '昪' => ' biàn', + '昩' => ' mò', + '昧' => ' mèi', + '昴' => ' mǎo', + '昦' => ' hào', + '春' => ' chūn', + '昤' => ' líng', + '昣' => ' zhěn', + '昢' => ' pò', + '昡' => ' xuàn', + '映' => ' yìng', + '星' => ' xīng', + '昞' => ' bǐng', + '昝' => ' zǎn', + '昳' => ' dié', + '昵' => ' nì', + '昛' => ' jù', + '時' => ' shí', + '晌' => ' shǎng', + '晋' => ' jìn', + '晊' => ' zhì', + '晉' => ' jìn', + '晈' => ' jiǎo', + '晇' => ' xū', + '晆' => ' kuí', + '晅' => ' xuǎn', + '晄' => ' huǎng', + '晃' => ' huǎng', + '晁' => ' cháo', + '昶' => ' chǎng', + '晀' => ' tiǎo', + '昿' => ' kuàng', + '显' => ' xiǎn', + '昽' => ' lóng', + '昼' => ' zhòu', + '昻' => ' áng', + '昺' => ' bǐng', + '昹' => ' ǎi', + '昸' => ' dōng', + '昷' => ' wēn', + '昜' => ' yáng', + '昚' => ' shèn', + '晎' => ' hǒng', + '旴' => ' xū', + '旾' => ' chūn', + '旽' => ' tùn', + '旼' => ' mín', + '旻' => ' mín', + '旺' => ' wàng', + '旹' => ' shí', + '旸' => ' yáng', + '旷' => ' kuàng', + '时' => ' shí', + '旵' => ' chǎn', + '旳' => ' dì', + '昀' => ' yún', + '旲' => ' tái', + '旱' => ' hàn', + '旰' => ' gàn', + '旯' => ' lá', + '旮' => ' gā', + '旭' => ' xù', + '旬' => ' xún', + '旫' => ' tiāo', + '旪' => ' xié', + '早' => ' zǎo', + '旿' => ' wǔ', + '昁' => ' bèi', + '昙' => ' tán', + '明' => ' míng', + '昘' => ' fǎng', + '昗' => ' zè', + '昖' => ' yán', + '昕' => ' xīn', + '昔' => ' xī', + '易' => ' yì', + '昒' => ' hū', + '昑' => ' qǐn', + '昐' => ' fēn', + '昏' => ' hūn', + '昍' => ' xuān', + '昂' => ' áng', + '昌' => ' chāng', + '昋' => ' guì', + '昊' => ' hào', + '昉' => ' fǎng', + '昈' => ' hù', + '昇' => ' shēng', + '昆' => ' kūn', + '昅' => ' jié', + '昄' => ' bǎn', + '昃' => ' zè', + '晍' => ' tóng', + '晏' => ' yàn', + '旧' => ' jiù', + '暐' => ' wěi', + '暚' => ' yáo', + '暙' => ' chūn', + '暘' => ' yáng', + '暗' => ' àn', + '暖' => ' nuǎn', + '暕' => ' jiǎn', + '暔' => ' nán', + '暓' => ' mào', + '暒' => ' qíng', + '暑' => ' shǔ', + '暏' => ' shǔ', + '暜' => ' jìn', + '暎' => ' yìng', + '暍' => ' yē', + '暌' => ' kuí', + '暋' => ' mǐn', + '暊' => ' xǔ', + '暉' => ' huī', + '暈' => ' yūn', + '暇' => ' xiá', + '暆' => ' yí', + '暅' => ' gèng', + '暛' => ' suǒ', + '暝' => ' míng', + '暃' => ' fei', + '暪' => ' mèn', + '暴' => ' bào', + '暳' => ' huì', + '暲' => ' zhāng', + '暱' => ' nì', + '暰' => ' cōng', + '暯' => ' mò', + '暮' => ' mù', + '暭' => ' hào', + '暬' => ' xiè', + '暫' => ' zàn', + '暩' => ' jì', + '暞' => ' jiǎo', + '暨' => ' jì', + '暧' => ' ài', + '暦' => ' lì', + '暥' => ' yàn', + '暤' => ' hào', + '暣' => ' qì', + '暢' => ' chàng', + '暡' => ' wěng', + '暠' => ' gǎo', + '暟' => ' kǎi', + '暄' => ' xuān', + '暂' => ' zàn', + '晐' => ' gāi', + '晜' => ' kūn', + '晦' => ' huì', + '晥' => ' hàn', + '晤' => ' wù', + '晣' => ' zhé', + '晢' => ' zhé', + '晡' => ' bū', + '晠' => ' shèng', + '晟' => ' chéng', + '晞' => ' xī', + '晝' => ' zhòu', + '晛' => ' xiàn', + '晨' => ' chén', + '晚' => ' wǎn', + '晙' => ' jùn', + '晘' => ' hàn', + '晗' => ' hán', + '晖' => ' huī', + '晕' => ' yūn', + '晔' => ' yè', + '晓' => ' xiǎo', + '晒' => ' shài', + '晑' => ' xiǎng', + '晧' => ' hào', + '晩' => ' wǎn', + '暁' => ' xiǎo', + '晶' => ' jīng', + '暀' => ' wǎng', + '晿' => ' chāng', + '晾' => ' liàng', + '晽' => ' lín', + '晼' => ' wǎn', + '晻' => ' àn', + '智' => ' zhì', + '晹' => ' yì', + '晸' => ' zhěng', + '晷' => ' guǐ', + '晵' => ' qǐ', + '晪' => ' tiǎn', + '晴' => ' qíng', + '晳' => ' xī', + '晲' => ' nǐ', + '晱' => ' shǎn', + '晰' => ' xī', + '景' => ' jǐng', + '普' => ' pǔ', + '晭' => ' zhǒu', + '晬' => ' zuì', + '晫' => ' zhuó', + '旨' => ' zhǐ', + '旦' => ' dàn', + '暶' => ' xuán', + '敖' => ' áo', + '敠' => ' duō', + '敟' => ' diǎn', + '敞' => ' chǎng', + '敝' => ' bì', + '敜' => ' niè', + '敛' => ' liǎn', + '敚' => ' duó', + '教' => ' jiào', + '敘' => ' xù', + '敗' => ' bài', + '敕' => ' chì', + '散' => ' sàn', + '敔' => ' yǔ', + '敓' => ' duó', + '敒' => ' shēn', + '救' => ' jiù', + '敐' => ' chén', + '敏' => ' mǐn', + '敎' => ' jiào', + '敍' => ' xù', + '敌' => ' dí', + '敋' => ' gé', + '敡' => ' yì', + '敤' => ' kě', + '敉' => ' mǐ', + '敱' => ' ái', + '敻' => ' xiòng', + '敺' => ' qū', + '敹' => ' liáo', + '數' => ' shù', + '敷' => ' fū', + '敶' => ' zhèn', + '敵' => ' dí', + '整' => ' zhěng', + '敳' => ' ái', + '敲' => ' qiāo', + '数' => ' shù', + '敥' => ' yàn', + '敯' => ' mín', + '敮' => ' xiá', + '敭' => ' yáng', + '敬' => ' jìng', + '敫' => ' jiǎo', + '敪' => ' duó', + '敩' => ' xiào', + '敨' => ' tǒu', + '敧' => ' jī', + '敦' => ' dūn', + '敊' => ' chù', + '效' => ' xiào', + '敽' => ' jiǎo', + '攢' => ' zǎn', + '攬' => ' lǎn', + '攫' => ' jué', + '攪' => ' jiǎo', + '攩' => ' dǎng', + '攨' => ' wā', + '攧' => ' diān', + '攦' => ' lì', + '攥' => ' zuàn', + '攤' => ' tān', + '攣' => ' luán', + '攡' => ' lí', + '攮' => ' nǎng', + '攠' => ' mí', + '攟' => ' jùn', + '攞' => ' luó', + '攝' => ' shè', + '攜' => ' xié', + '攛' => ' cuān', + '攚' => ' ying', + '攙' => ' chān', + '攘' => ' rǎng', + '攗' => ' méi', + '攭' => ' lì', + '支' => ' zhī', + '敇' => ' cè', + '攼' => ' gān', + '敆' => ' hé', + '故' => ' gù', + '敄' => ' wù', + '敃' => ' mǐn', + '敂' => ' kòu', + '敁' => ' diān', + '敀' => ' pò', + '政' => ' zhèng', + '放' => ' fàng', + '攽' => ' bān', + '攻' => ' gōng', + '攰' => ' guì', + '攺' => ' yǐ', + '改' => ' gǎi', + '攸' => ' yōu', + '攷' => ' kǎo', + '收' => ' shōu', + '攵' => ' pū', + '攴' => ' pū', + '攳' => ' xún', + '攲' => ' qī', + '攱' => ' guǐ', + '敼' => ' yǐ', + '敾' => ' shan', + '日' => ' rì', + '旀' => ' mèi', + '旊' => ' fǎng', + '旉' => ' fū', + '旈' => ' liú', + '旇' => ' pī', + '旆' => ' pèi', + '旅' => ' lǚ', + '旄' => ' máo', + '旃' => ' zhān', + '旂' => ' qí', + '旁' => ' páng', + '斿' => ' yóu', + '旌' => ' jīng', + '斾' => ' pèi', + '施' => ' shī', + '於' => ' yú', + '斻' => ' háng', + '斺' => ' chǎn', + '方' => ' fāng', + '斸' => ' zhǔ', + '斷' => ' duàn', + '斶' => ' chù', + '斵' => ' zhuó', + '旋' => ' xuán', + '旍' => ' jīng', + '斳' => ' qín', + '旚' => ' piāo', + '旤' => ' huò', + '旣' => ' jì', + '既' => ' jì', + '旡' => ' jì', + '无' => ' wú', + '旟' => ' yú', + '旞' => ' suì', + '旝' => ' kuài', + '旜' => ' zhān', + '旛' => ' fān', + '旙' => ' fān', + '旎' => ' nǐ', + '旘' => ' zhì', + '旗' => ' qí', + '旖' => ' yǐ', + '旕' => ' yú', + '旔' => ' jiàn', + '旓' => ' shāo', + '旒' => ' liú', + '旑' => ' yǐ', + '旐' => ' zhào', + '族' => ' zú', + '斴' => ' lín', + '斲' => ' zhuó', + '敿' => ' jiǎo', + '斋' => ' zhāi', + '斕' => ' lán', + '斔' => ' yǔ', + '斓' => ' lán', + '斒' => ' bān', + '斑' => ' bān', + '斐' => ' fěi', + '斏' => ' láng', + '斎' => ' zhāi', + '斍' => ' jué', + '斌' => ' bīn', + '斊' => ' qí', + '斗' => ' dòu', + '斉' => ' qí', + '斈' => ' xué', + '文' => ' wén', + '斆' => ' xiào', + '斅' => ' xiào', + '斄' => ' lí', + '斃' => ' bì', + '斂' => ' liǎn', + '斁' => ' yì', + '斀' => ' zhuó', + '斖' => ' wěi', + '斘' => ' shēng', + '斱' => ' zhuó', + '斦' => ' yín', + '新' => ' xīn', + '斯' => ' sī', + '斮' => ' cuò', + '断' => ' duàn', + '斬' => ' zhǎn', + '斫' => ' zhuó', + '斪' => ' qú', + '斩' => ' zhǎn', + '斨' => ' qiāng', + '斧' => ' fǔ', + '斥' => ' chì', + '料' => ' liào', + '斤' => ' jīn', + '斣' => ' dòu', + '斢' => ' tiǎo', + '斡' => ' wò', + '斠' => ' jiào', + '斟' => ' zhēn', + '斞' => ' yǔ', + '斝' => ' jiǎ', + '斜' => ' xié', + '斛' => ' hú', + '斚' => ' jiǎ', + '暵' => ' hàn', + '暷' => ' chuán', + '桖' => ' xuè', + '柉' => ' fán', + '染' => ' rǎn', + '柒' => ' qī', + '柑' => ' gān', + '某' => ' mǒu', + '柏' => ' bǎi', + '柎' => ' fū', + '柍' => ' yǎng', + '柌' => ' cí', + '柋' => ' dài', + '柊' => ' zhōng', + '柈' => ' bàn', + '柕' => ' mào', + '柇' => ' hé', + '柆' => ' lā', + '柅' => ' nǐ', + '柄' => ' bǐng', + '柃' => ' líng', + '柂' => ' yí', + '柁' => ' duò', + '柀' => ' bǐ', + '枿' => ' niè', + '枾' => ' shì', + '柔' => ' róu', + '柖' => ' sháo', + '枼' => ' yè', + '柣' => ' zhì', + '柭' => ' bā', + '柬' => ' jiǎn', + '柫' => ' fú', + '柪' => ' āo', + '柩' => ' jiù', + '柨' => ' bù', + '柧' => ' gū', + '柦' => ' dàn', + '查' => ' chá', + '柤' => ' zhā', + '柢' => ' dǐ', + '柗' => ' sōng', + '柡' => ' yǒng', + '柠' => ' níng', + '柟' => ' nán', + '柞' => ' zhà', + '柝' => ' tuò', + '柜' => ' guì', + '柛' => ' shēn', + '柚' => ' yòu', + '柙' => ' xiá', + '柘' => ' zhè', + '枽' => ' yè', + '枻' => ' yì', + '柯' => ' kē', + '枕' => ' zhěn', + '枟' => ' yùn', + '枞' => ' cōng', + '枝' => ' zhī', + '果' => ' guǒ', + '枛' => ' zhào', + '枚' => ' méi', + '枙' => ' ě', + '枘' => ' ruì', + '林' => ' lín', + '枖' => ' yāo', + '枔' => ' xín', + '枡' => ' dǒu', + '枓' => ' dǒu', + '枒' => ' yā', + '枑' => ' hù', + '析' => ' xī', + '枏' => ' nán', + '枎' => ' fú', + '枍' => ' yì', + '枌' => ' fén', + '枋' => ' fāng', + '枊' => ' àng', + '枠' => ' zui', + '枢' => ' shū', + '枺' => ' mò', + '枯' => ' kū', + '枹' => ' bāo', + '枸' => ' gǒu', + '枷' => ' jiā', + '架' => ' jià', + '枵' => ' xiāo', + '枴' => ' guǎi', + '枳' => ' zhǐ', + '枲' => ' xǐ', + '枱' => ' tái', + '枰' => ' píng', + '枮' => ' xiān', + '枣' => ' zǎo', + '枭' => ' xiāo', + '枬' => ' nán', + '枫' => ' fēng', + '枪' => ' qiāng', + '枩' => ' song', + '枨' => ' chéng', + '枧' => ' jiǎn', + '枦' => ' lu', + '枥' => ' lì', + '枤' => ' duo', + '柮' => ' duò', + '柰' => ' nài', + '枈' => ' bì', + '栱' => ' gǒng', + '栻' => ' shì', + '栺' => ' yì', + '根' => ' gēn', + '核' => ' hé', + '样' => ' yàng', + '栶' => ' yīn', + '栵' => ' liè', + '栴' => ' zhān', + '栳' => ' lǎo', + '栲' => ' kǎo', + '栰' => ' fá', + '栽' => ' zāi', + '栯' => ' yǒu', + '栮' => ' ěr', + '栭' => ' ér', + '栬' => ' zuì', + '栫' => ' jiàn', + '株' => ' zhū', + '栩' => ' xǔ', + '栨' => ' cì', + '栧' => ' yì', + '栦' => ' chóu', + '格' => ' gé', + '栾' => ' luán', + '栤' => ' bìng', + '桋' => ' yí', + '桕' => ' jiù', + '桔' => ' jú', + '桓' => ' huán', + '桒' => ' sāng', + '桑' => ' sāng', + '桐' => ' tóng', + '桏' => ' qióng', + '桎' => ' zhì', + '桍' => ' kū', + '桌' => ' zhuō', + '桊' => ' juàn', + '栿' => ' fú', + '桉' => ' ān', + '案' => ' àn', + '桇' => ' rú', + '框' => ' kuāng', + '桅' => ' wéi', + '桄' => ' guāng', + '桃' => ' táo', + '桂' => ' guì', + '桁' => ' héng', + '桀' => ' jié', + '栥' => ' zī', + '栣' => ' rěn', + '柱' => ' zhù', + '柽' => ' chēng', + '标' => ' biāo', + '栆' => ' zao', + '栅' => ' zhà', + '栄' => ' róng', + '栃' => ' li', + '栂' => ' méi', + '栁' => ' liǔ', + '栀' => ' zhī', + '柿' => ' shì', + '柾' => ' jiù', + '柼' => ' yǎo', + '栉' => ' zhì', + '査' => ' zhā', + '柺' => ' guǎi', + '柹' => ' shì', + '柸' => ' pēi', + '柷' => ' chù', + '柶' => ' sì', + '柵' => ' shān', + '柴' => ' chái', + '柳' => ' liǔ', + '柲' => ' bì', + '栈' => ' zhàn', + '栊' => ' lóng', + '栢' => ' bǎi', + '栗' => ' lì', + '校' => ' xiào', + '栠' => ' rěn', + '栟' => ' bēn', + '栞' => ' kān', + '栝' => ' guā', + '栜' => ' sè', + '栛' => ' lì', + '栚' => ' zhèn', + '栙' => ' xiáng', + '栘' => ' yí', + '栖' => ' qī', + '栋' => ' dòng', + '栕' => ' zhēn', + '栔' => ' qì', + '栓' => ' shuān', + '栒' => ' xún', + '树' => ' shù', + '栐' => ' yǒng', + '栏' => ' lán', + '栎' => ' lì', + '栍' => ' shēng', + '栌' => ' lú', + '枉' => ' wǎng', + '枇' => ' pí', + '暸' => ' liáo', + '書' => ' shū', + '朂' => ' xù', + '朁' => ' cǎn', + '最' => ' zuì', + '替' => ' tì', + '曾' => ' céng', + '曽' => ' cēng', + '曼' => ' màn', + '曻' => ' sheng', + '曺' => ' cáo', + '曹' => ' cáo', + '曷' => ' hé', + '朄' => ' yǐn', + '曶' => ' hū', + '曵' => ' yè', + '更' => ' gèng', + '曳' => ' yè', + '曲' => ' qū', + '曱' => ' yuē', + '曰' => ' yuē', + '曯' => ' zhú', + '曮' => ' yǎn', + '曭' => ' tǎng', + '會' => ' huì', + '朅' => ' qiè', + '曫' => ' luán', + '朒' => ' nǜ', + '朜' => ' tūn', + '望' => ' wàng', + '朚' => ' huāng', + '朙' => ' míng', + '朘' => ' zuī', + '朗' => ' lǎng', + '朖' => ' lǎng', + '朕' => ' zhèn', + '朔' => ' shuò', + '朓' => ' tiǎo', + '朑' => ' tì', + '朆' => ' fēn', + '朐' => ' qú', + '朏' => ' fěi', + '朎' => ' líng', + '服' => ' fú', + '朌' => ' fén', + '朋' => ' péng', + '朊' => ' ruǎn', + '有' => ' yǒu', + '月' => ' yuè', + '朇' => ' pí', + '曬' => ' shài', + '曪' => ' luǒ', + '朞' => ' jī', + '曄' => ' yè', + '曎' => ' yì', + '曍' => ' hào', + '曌' => ' zhào', + '曋' => ' shěn', + '曊' => ' fèi', + '曉' => ' xiǎo', + '曈' => ' tóng', + '曇' => ' tán', + '曆' => ' lì', + '曅' => ' yè', + '曃' => ' dài', + '曐' => ' xīng', + '曂' => ' huàng', + '曁' => ' jì', + '曀' => ' yì', + '暿' => ' xǐ', + '暾' => ' tūn', + '暽' => ' lín', + '暼' => ' piē', + '暻' => ' jǐng', + '暺' => ' dàn', + '暹' => ' xiān', + '曏' => ' xiǎng', + '曑' => ' shēn', + '曩' => ' nǎng', + '曞' => ' lì', + '曨' => ' lóng', + '曧' => ' róng', + '曦' => ' xī', + '曥' => ' lú', + '曤' => ' huò', + '曣' => ' yàn', + '曢' => ' liǎo', + '曡' => ' dié', + '曠' => ' kuàng', + '曟' => ' chén', + '曝' => ' pù', + '曒' => ' jiǎo', + '曜' => ' yào', + '曛' => ' xūn', + '曚' => ' méng', + '曙' => ' shǔ', + '曘' => ' rú', + '曗' => ' yè', + '曖' => ' ài', + '曕' => ' yàn', + '曔' => ' jìng', + '曓' => ' bào', + '朝' => ' cháo', + '期' => ' qī', + '枆' => ' máo', + '条' => ' tiáo', + '杫' => ' sì', + '杪' => ' miǎo', + '杩' => ' mà', + '杨' => ' yáng', + '杧' => ' máng', + '杦' => ' jiu', + '来' => ' lái', + '杤' => ' wan', + '杣' => ' shan', + '杢' => ' jiang', + '杠' => ' gāng', + '杭' => ' háng', + '束' => ' shù', + '杞' => ' qǐ', + '杝' => ' lí', + '杜' => ' dù', + '杛' => ' gōng', + '杚' => ' gài', + '杙' => ' yì', + '杘' => ' chì', + '杗' => ' máng', + '杖' => ' zhàng', + '杬' => ' yuán', + '杮' => ' fèi', + '杔' => ' tuō', + '杻' => ' chǒu', + '枅' => ' jī', + '构' => ' gòu', + '枃' => ' jìn', + '枂' => ' wò', + '极' => ' jí', + '枀' => ' sōng', + '板' => ' bǎn', + '松' => ' sōng', + '杽' => ' chǒu', + '杼' => ' zhù', + '杺' => ' xīn', + '杯' => ' bēi', + '杹' => ' huà', + '杸' => ' shū', + '杷' => ' pá', + '杶' => ' chūn', + '杵' => ' chǔ', + '杴' => ' xiān', + '杳' => ' yǎo', + '杲' => ' gǎo', + '東' => ' dōng', + '杰' => ' jié', + '杕' => ' dì', + '杓' => ' biāo', + '朠' => ' yīng', + '本' => ' běn', + '朶' => ' duǒ', + '朵' => ' duǒ', + '朴' => ' pǔ', + '朳' => ' bā', + '朲' => ' rén', + '朱' => ' zhū', + '朰' => ' mù', + '术' => ' shù', + '朮' => ' shù', + '札' => ' zhá', + '末' => ' mò', + '朸' => ' lì', + '未' => ' wèi', + '朩' => ' děng', + '木' => ' mù', + '朧' => ' lóng', + '朦' => ' méng', + '朥' => ' lao', + '朤' => ' lǎng', + '朣' => ' tóng', + '朢' => ' wàng', + '朡' => ' zōng', + '朷' => ' dāo', + '朹' => ' guǐ', + '杒' => ' rèn', + '杇' => ' wū', + '村' => ' cūn', + '材' => ' cái', + '杏' => ' xìng', + '李' => ' lǐ', + '杍' => ' zǐ', + '杌' => ' wù', + '杋' => ' fán', + '杊' => ' xún', + '杉' => ' shān', + '杈' => ' chā', + '杆' => ' gān', + '机' => ' jī', + '杅' => ' yú', + '杄' => ' qiān', + '权' => ' quán', + '杂' => ' zá', + '杁' => ' ru', + '杀' => ' shā', + '朿' => ' cì', + '朾' => ' chéng', + '朽' => ' xiǔ', + '朼' => ' bǐ', + '朻' => ' jiū', + '应' => ' yīng', + '庒' => ' zhuang', + '再' => ' zài', + '嗟' => ' jiē', + '嗪' => ' qín', + '嗩' => ' suǒ', + '嗨' => ' hāi', + '嗦' => ' suo', + '嗥' => ' háo', + '嗤' => ' chī', + '嗣' => ' sì', + '嗢' => ' wà', + '嗡' => ' wēng', + '嗠' => ' luò', + '嗞' => ' zī', + '嗬' => ' hē', + '嗝' => ' gé', + '嗜' => ' shì', + '嗛' => ' qiǎn', + '嗚' => ' wū', + '嗙' => ' pǎng', + '嗘' => ' jī', + '嗗' => ' wā', + '嗖' => ' sōu', + '嗕' => ' rù', + '嗔' => ' chēn', + '嗫' => ' niè', + '嗭' => ' zhí', + '嗒' => ' dā', + '嗺' => ' zuī', + '嘄' => ' jiāo', + '嘃' => ' chōng', + '嘂' => ' jiào', + '嘁' => ' qī', + '嘀' => ' dí', + '嗿' => ' tǎn', + '嗾' => ' sǒu', + '嗽' => ' sòu', + '嗼' => ' mò', + '嗻' => ' zhē', + '嗹' => ' lián', + '嗮' => ' sài', + '嗸' => ' áo', + '嗷' => ' áo', + '嗶' => ' bì', + '嗵' => ' tōng', + '嗴' => ' qiang', + '嗳' => ' āi', + '嗲' => ' diǎ', + '嗱' => ' ná', + '嗰' => ' gè', + '嗯' => ' èn', + '嗓' => ' sǎng', + '嗑' => ' kē', + '嘆' => ' tàn', + '喫' => ' chī', + '喵' => ' miāo', + '喴' => ' wēi', + '喳' => ' zhā', + '喲' => ' yō', + '喱' => ' lí', + '喰' => ' cān', + '喯' => ' pèn', + '單' => ' dān', + '喭' => ' yàn', + '喬' => ' qiáo', + '喪' => ' sàng', + '喷' => ' pēn', + '喩' => ' yù', + '喨' => ' liàng', + '喧' => ' xuān', + '喦' => ' niè', + '喥' => ' duó', + '喤' => ' huáng', + '喣' => ' xù', + '喢' => ' shà', + '喡' => ' wéi', + '喠' => ' zhǒng', + '営' => ' yíng', + '喸' => ' bǔ', + '嗐' => ' hài', + '嗅' => ' xiù', + '嗏' => ' chā', + '嗎' => ' ma', + '嗍' => ' suō', + '嗌' => ' ài', + '嗋' => ' xié', + '嗊' => ' hǒng', + '嗉' => ' sù', + '嗈' => ' yōng', + '嗇' => ' sè', + '嗆' => ' qiāng', + '嗄' => ' á', + '喹' => ' kuí', + '嗃' => ' hè', + '嗂' => ' yáo', + '嗁' => ' tí', + '嗀' => ' hù', + '喿' => ' zào', + '喾' => ' kù', + '喽' => ' lóu', + '喼' => ' jié', + '喻' => ' yù', + '喺' => ' xì', + '嘅' => ' kǎi', + '嘇' => ' shān', + '喞' => ' jī', + '噈' => ' cù', + '噒' => ' lián', + '噑' => ' háo', + '噐' => ' qì', + '噏' => ' xī', + '噎' => ' yē', + '噍' => ' jiào', + '噌' => ' cēng', + '噋' => ' tūn', + '噊' => ' yù', + '噉' => ' dàn', + '噇' => ' chuáng', + '噔' => ' dēng', + '噆' => ' zǎn', + '噅' => ' huī', + '噄' => ' chī', + '噃' => ' fān', + '噂' => ' zǔn', + '噁' => ' ě', + '噀' => ' xùn', + '嘿' => ' hēi', + '嘾' => ' dàn', + '嘽' => ' chǎn', + '噓' => ' xū', + '噕' => ' huī', + '嘻' => ' xī', + '噢' => ' ō', + '噬' => ' shì', + '噫' => ' yī', + '噪' => ' zào', + '噩' => ' è', + '器' => ' qì', + '噧' => ' xiè', + '噦' => ' huì', + '噥' => ' nóng', + '噤' => ' jìn', + '噣' => ' zhòu', + '噡' => ' zhān', + '噖' => ' yín', + '噠' => ' dā', + '噟' => ' yìng', + '噞' => ' yǎn', + '噝' => ' sī', + '噜' => ' lū', + '噛' => ' niè', + '噚' => ' xún', + '噙' => ' qín', + '噘' => ' juē', + '噗' => ' pū', + '嘼' => ' chù', + '嘺' => ' qiáo', + '嘈' => ' cáo', + '嘔' => ' ǒu', + '嘞' => ' lei', + '嘝' => ' hú', + '嘜' => ' mà', + '嘛' => ' ma', + '嘚' => ' dē', + '嘙' => ' pó', + '嘘' => ' xū', + '嘗' => ' cháng', + '嘖' => ' zé', + '嘕' => ' xiān', + '嘓' => ' guō', + '嘠' => ' gā', + '嘒' => ' huì', + '嘑' => ' hū', + '嘐' => ' xiāo', + '嘏' => ' gǔ', + '嘎' => ' gā', + '嘍' => ' lóu', + '嘌' => ' piào', + '嘋' => ' xiāo', + '嘊' => ' ái', + '嘉' => ' jiā', + '嘟' => ' dū', + '嘡' => ' tāng', + '嘹' => ' liáo', + '嘮' => ' láo', + '嘸' => ' fǔ', + '嘷' => ' háo', + '嘶' => ' sī', + '嘵' => ' xiāo', + '嘴' => ' zuǐ', + '嘳' => ' kuì', + '嘲' => ' cháo', + '嘱' => ' zhǔ', + '嘰' => ' jī', + '嘯' => ' xiào', + '嘭' => ' pēng', + '嘢' => ' yě', + '嘬' => ' chuài', + '嘫' => ' rán', + '嘪' => ' mǎi', + '嘩' => ' huā', + '嘨' => ' xiào', + '嘧' => ' mì', + '嘦' => ' jiào', + '嘥' => ' sai', + '嘤' => ' yīng', + '嘣' => ' bēng', + '喟' => ' kuì', + '喝' => ' hē', + '噮' => ' yuàn', + '唏' => ' xī', + '唙' => ' dí', + '唘' => ' qǐ', + '唗' => ' dōu', + '唖' => ' yǎ', + '唕' => ' zào', + '唔' => ' wú', + '唓' => ' chē', + '唒' => ' qiú', + '唑' => ' zuò', + '唐' => ' táng', + '唎' => ' lì', + '唛' => ' mà', + '唍' => ' wǎn', + '唌' => ' xián', + '唋' => ' tū', + '唊' => ' jiá', + '唉' => ' āi', + '唈' => ' yì', + '唇' => ' chún', + '唆' => ' suō', + '唅' => ' hán', + '唄' => ' bei', + '唚' => ' qìn', + '唜' => ' mò', + '唂' => ' gū', + '唩' => ' wō', + '唳' => ' lì', + '唲' => ' ér', + '唱' => ' chàng', + '唰' => ' shuā', + '唯' => ' wéi', + '售' => ' shòu', + '唭' => ' qì', + '唬' => ' hǔ', + '唫' => ' jìn', + '唪' => ' fěng', + '唨' => ' zuǒ', + '唝' => ' gòng', + '唧' => ' jī', + '唦' => ' shā', + '唥' => ' lang', + '唤' => ' huàn', + '唣' => ' zào', + '唢' => ' suǒ', + '唡' => ' liǎng', + '唠' => ' láo', + '唟' => ' qù', + '唞' => ' dǒu', + '唃' => ' gǔ', + '唁' => ' yàn', + '唵' => ' ǎn', + '哛' => ' fēn', + '哥' => ' gē', + '哤' => ' máng', + '哣' => ' pǒu', + '哢' => ' lòng', + '員' => ' yuán', + '哠' => ' hào', + '哟' => ' yō', + '哞' => ' mōu', + '哝' => ' nóng', + '哜' => ' jì', + '哚' => ' duǒ', + '哧' => ' chī', + '哙' => ' kuài', + '哘' => ' xing', + '哗' => ' huā', + '哖' => ' nián', + '哕' => ' huì', + '哔' => ' bì', + '哓' => ' xiāo', + '哒' => ' dā', + '哑' => ' yǎ', + '哐' => ' kuāng', + '哦' => ' ó', + '哨' => ' shào', + '唀' => ' yòu', + '哵' => ' bā', + '哿' => ' gě', + '哾' => ' shuō', + '哽' => ' gěng', + '哼' => ' hēng', + '哻' => ' hàn', + '哺' => ' bǔ', + '哹' => ' fú', + '哸' => ' suī', + '哷' => ' liè', + '哶' => ' miē', + '哴' => ' liàng', + '哩' => ' lī', + '哳' => ' zhā', + '哲' => ' zhé', + '哱' => ' bō', + '哰' => ' láo', + '哯' => ' xiàn', + '哮' => ' xiāo', + '哭' => ' kū', + '哬' => ' hé', + '哫' => ' zú', + '哪' => ' nǎ', + '唴' => ' qiàng', + '唶' => ' zé', + '喜' => ' xǐ', + '啷' => ' lāng', + '喁' => ' yóng', + '喀' => ' kā', + '啿' => ' dàn', + '啾' => ' jiū', + '啽' => ' án', + '啼' => ' tí', + '啻' => ' chì', + '啺' => ' táng', + '啹' => ' jú', + '啸' => ' xiào', + '啶' => ' dìng', + '喃' => ' nán', + '啵' => ' bo', + '啴' => ' chǎn', + '啳' => ' quán', + '啲' => ' dì', + '啱' => ' yān', + '啰' => ' luō', + '啯' => ' guō', + '啮' => ' niè', + '啭' => ' zhuàn', + '啬' => ' sè', + '喂' => ' wèi', + '善' => ' shàn', + '啪' => ' pā', + '喑' => ' yīn', + '喛' => ' huàn', + '喚' => ' huàn', + '喙' => ' huì', + '喘' => ' chuǎn', + '喗' => ' yǔn', + '喖' => ' hú', + '喕' => ' miǎn', + '喔' => ' ō', + '喓' => ' yāo', + '喒' => ' zá', + '喐' => ' yù', + '喅' => ' yù', + '喏' => ' nuò', + '喎' => ' wāi', + '喍' => ' chái', + '喌' => ' zhōu', + '喋' => ' dié', + '喊' => ' hǎn', + '喉' => ' hóu', + '喈' => ' jiē', + '喇' => ' lǎ', + '喆' => ' zhé', + '啫' => ' zhě', + '啩' => ' guà', + '唷' => ' yō', + '啃' => ' kěn', + '啍' => ' tūn', + '啌' => ' xiāng', + '啋' => ' cǎi', + '啊' => ' a', + '啉' => ' lín', + '啈' => ' hēng', + '啇' => ' dì', + '商' => ' shāng', + '啅' => ' zhuó', + '啄' => ' zhuó', + '啂' => ' nǒu', + '問' => ' wèn', + '啁' => ' zhāo', + '啀' => ' ái', + '唿' => ' hū', + '唾' => ' tuò', + '唽' => ' xī', + '唼' => ' shà', + '唻' => ' lài', + '唺' => ' tiǎn', + '唹' => ' yū', + '唸' => ' niàn', + '啎' => ' wǔ', + '啐' => ' cuì', + '啨' => ' yīng', + '啝' => ' hé', + '啧' => ' zé', + '啦' => ' la', + '啥' => ' shà', + '啤' => ' pí', + '啣' => ' xián', + '啢' => ' liǎng', + '啡' => ' fēi', + '啠' => ' zhé', + '啟' => ' qǐ', + '啞' => ' yǎ', + '啜' => ' chuài', + '啑' => ' shà', + '啛' => ' cuì', + '啚' => ' bǐ', + '啙' => ' zǐ', + '啘' => ' yè', + '啗' => ' dàn', + '啖' => ' dàn', + '啕' => ' táo', + '啔' => ' qǐ', + '啓' => ' qǐ', + '啒' => ' gǔ', + '噭' => ' jiào', + '噯' => ' āi', + '哎' => ' āi', + '垁' => ' zhì', + '型' => ' xíng', + '垊' => ' min', + '垉' => ' páo', + '垈' => ' dài', + '垇' => ' ào', + '垆' => ' lú', + '垅' => ' lǒng', + '垄' => ' lǒng', + '垃' => ' lā', + '垂' => ' chuí', + '垀' => ' hū', + '垍' => ' jì', + '坿' => ' fù', + '坾' => ' zhù', + '坽' => ' líng', + '坼' => ' chè', + '坻' => ' chí', + '坺' => ' bá', + '坹' => ' xuè', + '坸' => ' gòu', + '坷' => ' kě', + '坶' => ' mǔ', + '垌' => ' dòng', + '垎' => ' hè', + '坴' => ' lù', + '垛' => ' duǒ', + '垥' => ' xié', + '垤' => ' dié', + '垣' => ' yuán', + '垢' => ' gòu', + '垡' => ' fá', + '垠' => ' yín', + '垟' => ' yáng', + '垞' => ' chá', + '垝' => ' guǐ', + '垜' => ' duǒ', + '垚' => ' yáo', + '垏' => ' lǜ', + '垙' => ' guāng', + '垘' => ' fú', + '垗' => ' zhào', + '垖' => ' duī', + '垕' => ' hòu', + '垔' => ' yīn', + '垓' => ' gāi', + '垒' => ' lěi', + '垑' => ' chǐ', + '垐' => ' cí', + '坵' => ' qiū', + '坳' => ' ào', + '垧' => ' shǎng', + '坍' => ' tān', + '块' => ' kuài', + '坖' => ' jì', + '坕' => ' jīng', + '坔' => ' dì', + '坓' => ' jǐng', + '坒' => ' bì', + '坑' => ' kēng', + '坐' => ' zuò', + '坏' => ' huài', + '坎' => ' kǎn', + '坌' => ' bèn', + '坙' => ' jīng', + '坋' => ' bèn', + '坊' => ' fāng', + '坉' => ' tún', + '坈' => ' rǒng', + '均' => ' jūn', + '坆' => ' méi', + '坅' => ' qǐn', + '坄' => ' yì', + '坃' => ' xūn', + '坂' => ' bǎn', + '坘' => ' dǐ', + '坚' => ' jiān', + '坲' => ' fó', + '坧' => ' zhī', + '坱' => ' yǎng', + '坰' => ' jiōng', + '坯' => ' pī', + '坮' => ' tái', + '坭' => ' ní', + '坬' => ' guà', + '坫' => ' diàn', + '坪' => ' píng', + '坩' => ' gān', + '坨' => ' tuó', + '坦' => ' tǎn', + '坛' => ' tán', + '坥' => ' qū', + '坤' => ' kūn', + '坣' => ' tāng', + '坢' => ' bàn', + '坡' => ' pō', + '坠' => ' zhuì', + '坟' => ' fén', + '坞' => ' wù', + '坝' => ' bà', + '坜' => ' lì', + '垦' => ' kěn', + '垨' => ' shǒu', + '址' => ' zhǐ', + '埩' => ' zhēng', + '埳' => ' kǎn', + '埲' => ' běng', + '埱' => ' chù', + '埰' => ' cài', + '埯' => ' ǎn', + '埮' => ' tàn', + '埭' => ' dài', + '埬' => ' dōng', + '埫' => ' chǒng', + '埪' => ' kōng', + '埨' => ' lǔn', + '埵' => ' duǒ', + '埧' => ' jù', + '埦' => ' wǎn', + '埥' => ' qīng', + '埤' => ' pí', + '埣' => ' suì', + '埢' => ' quán', + '埡' => ' yā', + '埠' => ' bù', + '域' => ' yù', + '埞' => ' dǐ', + '埴' => ' zhí', + '埶' => ' yì', + '埜' => ' yě', + '堃' => ' kūn', + '堍' => ' tù', + '堌' => ' gù', + '堋' => ' péng', + '堊' => ' è', + '堉' => ' yù', + '堈' => ' gāng', + '堇' => ' jǐn', + '堆' => ' duī', + '堅' => ' jiān', + '堄' => ' nì', + '堂' => ' táng', + '執' => ' zhí', + '堁' => ' kè', + '堀' => ' kū', + '埿' => ' ní', + '埾' => ' jù', + '埽' => ' sào', + '埼' => ' qí', + '埻' => ' zhǔn', + '基' => ' jī', + '培' => ' péi', + '埸' => ' yì', + '埝' => ' niàn', + '埛' => ' jiōng', + '垩' => ' è', + '垵' => ' ǎn', + '垿' => ' xù', + '垾' => ' hàn', + '垽' => ' yìn', + '垼' => ' yì', + '垻' => ' bà', + '垺' => ' fū', + '垹' => ' bāng', + '垸' => ' yuàn', + '垷' => ' xiàn', + '垶' => ' xīng', + '垴' => ' nǎo', + '埁' => ' qín', + '垳' => ' hang', + '垲' => ' kǎi', + '垱' => ' dàng', + '垰' => ' ka', + '垯' => ' da', + '垮' => ' kuǎ', + '垭' => ' yā', + '垬' => ' hóng', + '垫' => ' diàn', + '垪' => ' bing', + '埀' => ' chuí', + '埂' => ' gěng', + '埚' => ' guō', + '埏' => ' shān', + '埙' => ' xūn', + '埘' => ' shí', + '埗' => ' bù', + '埖' => ' hua', + '埕' => ' chéng', + '埔' => ' bù', + '埓' => ' liè', + '埒' => ' liè', + '埑' => ' zhé', + '埐' => ' jīn', + '城' => ' chéng', + '埃' => ' āi', + '埍' => ' juǎn', + '埌' => ' làng', + '埋' => ' mái', + '埊' => ' dì', + '埉' => ' jiā', + '埈' => ' jùn', + '埇' => ' yǒng', + '埆' => ' què', + '埅' => ' fáng', + '埄' => ' běng', + '坁' => ' zhǐ', + '圿' => ' jiá', + '噰' => ' yōng', + '嚰' => ' mó', + '嚺' => ' tà', + '嚹' => ' lá', + '嚸' => ' diǎn', + '嚷' => ' rǎng', + '嚶' => ' yīng', + '嚵' => ' chán', + '嚴' => ' yán', + '嚳' => ' kù', + '嚲' => ' duǒ', + '嚱' => ' xì', + '嚯' => ' huò', + '嚼' => ' jué', + '嚮' => ' xiàng', + '嚭' => ' pǐ', + '嚬' => ' pín', + '嚫' => ' chèn', + '嚪' => ' dàn', + '嚩' => ' mó', + '嚨' => ' lóng', + '嚧' => ' lú', + '嚦' => ' lì', + '嚥' => ' yàn', + '嚻' => ' xiāo', + '嚽' => ' chuò', + '嚣' => ' xiāo', + '囊' => ' náng', + '囔' => ' nāng', + '囓' => ' niè', + '囒' => ' lán', + '囑' => ' zhǔ', + '囐' => ' zá', + '囏' => ' jiān', + '囎' => ' zen', + '囍' => ' xǐ', + '囌' => ' sū', + '囋' => ' zá', + '囉' => ' luō', + '嚾' => ' huān', + '囈' => ' yì', + '囇' => ' lì', + '囆' => ' chài', + '囅' => ' chǎn', + '囄' => ' lí', + '囃' => ' cà', + '囂' => ' xiāo', + '囁' => ' niè', + '囀' => ' zhuàn', + '嚿' => ' huò', + '嚤' => ' mó', + '嚢' => ' náng', + '囖' => ' lo', + '噼' => ' pī', + '嚆' => ' hāo', + '嚅' => ' rú', + '嚄' => ' huō', + '嚃' => ' tā', + '嚂' => ' làn', + '嚁' => ' dí', + '嚀' => ' níng', + '噿' => ' zuǐ', + '噾' => ' yīn', + '噽' => ' pǐ', + '噻' => ' sāi', + '嚈' => ' yè', + '噺' => ' xin', + '噹' => ' dāng', + '噸' => ' dūn', + '噷' => ' hm', + '噶' => ' gá', + '噵' => ' dào', + '噴' => ' pēn', + '噳' => ' yǔ', + '噲' => ' kuài', + '噱' => ' jué', + '嚇' => ' xià', + '嚉' => ' duō', + '嚡' => ' hai', + '嚖' => ' huì', + '嚠' => ' liú', + '嚟' => ' lí', + '嚞' => ' zhé', + '嚝' => ' hōng', + '嚜' => ' me', + '嚛' => ' hù', + '嚚' => ' yín', + '嚙' => ' niè', + '嚘' => ' yōu', + '嚗' => ' bó', + '嚕' => ' lǔ', + '嚊' => ' pì', + '嚔' => ' tì', + '嚓' => ' cā', + '嚒' => ' me', + '嚑' => ' xun', + '嚐' => ' cháng', + '嚏' => ' tì', + '嚎' => ' háo', + '嚍' => ' jìn', + '嚌' => ' jì', + '嚋' => ' chóu', + '囕' => ' lǎn', + '囗' => ' wéi', + '圾' => ' jī', + '圙' => ' lüè', + '圣' => ' shèng', + '圢' => ' tǐng', + '圡' => ' tǔ', + '圠' => ' yà', + '土' => ' tǔ', + '圞' => ' luán', + '圝' => ' luán', + '圜' => ' huán', + '圛' => ' yì', + '圚' => ' huì', + '團' => ' tuán', + '圥' => ' lù', + '圗' => ' tú', + '圖' => ' tú', + '圕' => ' tú', + '圔' => ' yà', + '圓' => ' yuán', + '園' => ' yuán', + '圑' => ' fù', + '圐' => ' kū', + '圏' => ' quān', + '圎' => ' yuán', + '圤' => ' pǔ', + '圦' => ' kuai', + '圌' => ' chuán', + '圳' => ' zhèn', + '圽' => ' mò', + '圼' => ' niè', + '圻' => ' qí', + '场' => ' chǎng', + '圹' => ' kuàng', + '圸' => ' shan', + '圷' => ' xia', + '圶' => ' qià', + '圵' => ' dàng', + '圴' => ' zhuó', + '圲' => ' qiān', + '圧' => ' yā', + '圱' => ' qiān', + '地' => ' dì', + '圯' => ' yí', + '圮' => ' pǐ', + '圭' => ' guī', + '圬' => ' wū', + '圫' => ' yù', + '圪' => ' gē', + '圩' => ' wéi', + '在' => ' zài', + '圍' => ' wéi', + '國' => ' guó', + '囘' => ' huí', + '囤' => ' dùn', + '囮' => ' é', + '园' => ' yuán', + '囬' => ' huí', + '囫' => ' hú', + '囪' => ' cōng', + '囩' => ' yún', + '囨' => ' piān', + '囧' => ' jiǒng', + '囦' => ' yuān', + '囥' => ' kàng', + '団' => ' tuán', + '困' => ' kùn', + '团' => ' tuán', + '囡' => ' nān', + '因' => ' yīn', + '囟' => ' xìn', + '回' => ' huí', + '囝' => ' jiǎn', + '囜' => ' nín', + '四' => ' sì', + '囚' => ' qiú', + '囙' => ' yīn', + '囯' => ' guó', + '囱' => ' cōng', + '圊' => ' qīng', + '囿' => ' yòu', + '圉' => ' yǔ', + '圈' => ' quān', + '圇' => ' lún', + '圆' => ' yuán', + '圅' => ' hán', + '圄' => ' yǔ', + '圃' => ' pǔ', + '圂' => ' hùn', + '圁' => ' yín', + '圀' => ' guó', + '图' => ' tú', + '囲' => ' tōng', + '国' => ' guó', + '囼' => ' tāi', + '囻' => ' guó', + '固' => ' gù', + '囹' => ' líng', + '囸' => ' rì', + '囷' => ' qūn', + '囶' => ' guó', + '囵' => ' lún', + '围' => ' wéi', + '図' => ' tú', + '哏' => ' gén', + '响' => ' xiǎng', + '堏' => ' fang', + '办' => ' bàn', + '动' => ' dòng', + '劧' => ' zhǐ', + '劦' => ' xié', + '劥' => ' kēng', + '劤' => ' jìn', + '劣' => ' liè', + '劢' => ' mài', + '务' => ' wù', + '加' => ' jiā', + '功' => ' gōng', + '劝' => ' quàn', + '努' => ' nǔ', + '劜' => ' yà', + '力' => ' lì', + '劚' => ' zhǔ', + '劙' => ' lí', + '劘' => ' mó', + '劗' => ' jiǎn', + '劖' => ' chán', + '劕' => ' zhì', + '劔' => ' jiàn', + '劓' => ' yì', + '助' => ' zhù', + '劫' => ' jié', + '劑' => ' jì', + '劸' => ' wā', + '勂' => ' gào', + '勁' => ' jìn', + '勀' => ' kè', + '势' => ' shì', + '劾' => ' hé', + '劽' => ' liè', + '劼' => ' jié', + '劻' => ' kuāng', + '劺' => ' móu', + '効' => ' xiào', + '劷' => ' yáng', + '劬' => ' qú', + '劶' => ' kǒu', + '劵' => ' juàn', + '労' => ' láo', + '劳' => ' láo', + '劲' => ' jìn', + '励' => ' lì', + '劰' => ' mò', + '劯' => ' zhū', + '劮' => ' yì', + '劭' => ' shào', + '劒' => ' jiàn', + '劐' => ' huō', + '勄' => ' mǐn', + '剪' => ' jiǎn', + '剴' => ' kǎi', + '剳' => ' dá', + '割' => ' gē', + '剱' => ' jiàn', + '剰' => ' shèng', + '副' => ' fù', + '剮' => ' guǎ', + '剭' => ' wū', + '剬' => ' duān', + '剫' => ' duó', + '剩' => ' shèng', + '剶' => ' chuān', + '剨' => ' huō', + '剧' => ' jù', + '剦' => ' yān', + '剥' => ' bō', + '剤' => ' jì', + '剣' => ' jiàn', + '剢' => ' dū', + '剡' => ' shàn', + '剠' => ' qíng', + '剟' => ' duō', + '創' => ' chuàng', + '剷' => ' chǎn', + '劏' => ' tāng', + '劄' => ' zhā', + '劎' => ' jiàn', + '劍' => ' jiàn', + '劌' => ' guì', + '劋' => ' jiǎo', + '劊' => ' guì', + '劉' => ' liú', + '劈' => ' pī', + '劇' => ' jù', + '劆' => ' lián', + '劅' => ' zhuò', + '劃' => ' huà', + '剸' => ' tuán', + '劂' => ' jué', + '劁' => ' qiāo', + '劀' => ' guā', + '剿' => ' jiǎo', + '剾' => ' kōu', + '剽' => ' piāo', + '剼' => ' shān', + '剻' => ' pěng', + '剺' => ' lí', + '剹' => ' lù', + '勃' => ' bó', + '勅' => ' chì', + '剝' => ' bō', + '匆' => ' cōng', + '匐' => ' fú', + '匏' => ' páo', + '匎' => ' è', + '匍' => ' pú', + '匌' => ' gé', + '匋' => ' táo', + '匊' => ' jū', + '匉' => ' pēng', + '匈' => ' xiōng', + '匇' => ' yi', + '包' => ' bāo', + '匒' => ' dá', + '匄' => ' gài', + '匃' => ' gài', + '匂' => ' bi', + '匁' => ' wén', + '匀' => ' yún', + '勿' => ' wù', + '勾' => ' gōu', + '勽' => ' bào', + '勼' => ' jiū', + '勻' => ' yún', + '匑' => ' gōng', + '匓' => ' jiù', + '勹' => ' bāo', + '匠' => ' jiàng', + '匪' => ' fěi', + '匩' => ' kuāng', + '匨' => ' zāng', + '匧' => ' qiè', + '匦' => ' guǐ', + '匥' => ' biàn', + '匤' => ' qū', + '匣' => ' xiá', + '匢' => ' hū', + '匡' => ' kuāng', + '匟' => ' kàng', + '匔' => ' qiōng', + '匞' => ' jiàng', + '匝' => ' zā', + '匜' => ' yí', + '匛' => ' jiù', + '匚' => ' fāng', + '匙' => ' shi', + '匘' => ' nǎo', + '北' => ' běi', + '化' => ' huà', + '匕' => ' bǐ', + '勺' => ' sháo', + '勸' => ' quàn', + '勆' => ' láng', + '勒' => ' lēi', + '勜' => ' wěng', + '勛' => ' xūn', + '勚' => ' yì', + '務' => ' wù', + '勘' => ' kān', + '勗' => ' xù', + '勖' => ' xù', + '動' => ' dòng', + '勔' => ' miǎn', + '勓' => ' kài', + '勑' => ' chì', + '勞' => ' láo', + '勐' => ' měng', + '勏' => ' bù', + '勎' => ' lù', + '勍' => ' qíng', + '勌' => ' juàn', + '勋' => ' xūn', + '勊' => ' kè', + '勉' => ' miǎn', + '勈' => ' yǒng', + '勇' => ' yǒng', + '勝' => ' shèng', + '募' => ' mù', + '勷' => ' ráng', + '勬' => ' juān', + '勶' => ' chè', + '勵' => ' lì', + '勴' => ' lǜ', + '勳' => ' xūn', + '勲' => ' xūn', + '勱' => ' mài', + '勰' => ' xié', + '勯' => ' dān', + '勮' => ' jù', + '勭' => ' tóng', + '勫' => ' fān', + '勠' => ' lù', + '勪' => ' jué', + '勩' => ' yì', + '勨' => ' xiàng', + '勧' => ' quàn', + '勦' => ' chāo', + '勥' => ' jiàng', + '勤' => ' qín', + '勣' => ' jī', + '勢' => ' shì', + '勡' => ' piào', + '剞' => ' jī', + '剜' => ' wān', + '匬' => ' yǔ', + '凍' => ' dòng', + '凗' => ' cuī', + '凖' => ' zhun', + '凕' => ' mǐng', + '凔' => ' chuàng', + '凓' => ' lì', + '凒' => ' yí', + '凑' => ' còu', + '凐' => ' yīn', + '减' => ' jiǎn', + '凎' => ' gàn', + '凌' => ' líng', + '凙' => ' duó', + '凋' => ' diāo', + '凊' => ' qìng', + '凉' => ' liáng', + '凈' => ' jìng', + '凇' => ' sōng', + '准' => ' zhǔn', + '凅' => ' gù', + '凄' => ' qī', + '凃' => ' tú', + '凂' => ' měi', + '凘' => ' sī', + '凚' => ' jìn', + '净' => ' jìng', + '凧' => ' zheng', + '凱' => ' kǎi', + '凰' => ' huáng', + '凯' => ' kǎi', + '凮' => ' fēng', + '凭' => ' píng', + '凬' => ' fēng', + '凫' => ' fú', + '凪' => ' zhi', + '凩' => ' mu', + '凨' => ' fēng', + '処' => ' chǔ', + '凛' => ' lǐn', + '凥' => ' jū', + '凤' => ' fèng', + '凣' => ' fán', + '凢' => ' fán', + '凡' => ' fán', + '几' => ' jǐ', + '凟' => ' dú', + '凞' => ' xī', + '凝' => ' níng', + '凜' => ' lǐn', + '凁' => ' shù', + '冿' => ' jiān', + '凳' => ' dèng', + '写' => ' xiě', + '冣' => ' jù', + '冢' => ' zhǒng', + '冡' => ' méng', + '冠' => ' guān', + '冟' => ' shì', + '冞' => ' mí', + '冝' => ' yí', + '农' => ' nóng', + '军' => ' jūn', + '冚' => ' kǎn', + '冘' => ' yín', + '冥' => ' míng', + '冗' => ' rǒng', + '冖' => ' mì', + '冕' => ' miǎn', + '冔' => ' xǔ', + '冓' => ' gòu', + '冒' => ' mào', + '冑' => ' zhòu', + '冐' => ' mào', + '冏' => ' jiǒng', + '冎' => ' guǎ', + '冤' => ' yuān', + '冦' => ' kòu', + '冾' => ' qià', + '决' => ' jué', + '冽' => ' liè', + '冼' => ' xiǎn', + '冻' => ' dòng', + '冺' => ' mǐn', + '冹' => ' fú', + '冸' => ' pàn', + '冷' => ' lěng', + '冶' => ' yě', + '况' => ' kuàng', + '冴' => ' hù', + '冲' => ' chōng', + '冧' => ' lín', + '冱' => ' hù', + '冰' => ' bīng', + '冯' => ' féng', + '冮' => ' gāng', + '冭' => ' tái', + '冬' => ' dōng', + '冫' => ' bīng', + '冪' => ' mì', + '冩' => ' xiě', + '冨' => ' fù', + '凲' => ' gān', + '凴' => ' píng', + '剛' => ' gāng', + '制' => ' zhì', + '剀' => ' kǎi', + '刿' => ' guì', + '刾' => ' cì', + '刽' => ' guì', + '刼' => ' jié', + '刻' => ' kè', + '刺' => ' cì', + '刹' => ' shā', + '券' => ' quàn', + '刷' => ' shuā', + '刵' => ' èr', + '剂' => ' jì', + '刴' => ' duò', + '刳' => ' kū', + '刲' => ' kuī', + '刱' => ' chuàng', + '到' => ' dào', + '刯' => ' gēng', + '刮' => ' guā', + '刭' => ' jǐng', + '刬' => ' chǎn', + '别' => ' bié', + '剁' => ' duò', + '剃' => ' tì', + '利' => ' lì', + '剐' => ' guǎ', + '剚' => ' zì', + '剙' => ' chuàng', + '剘' => ' qí', + '剗' => ' chǎn', + '剖' => ' pōu', + '剕' => ' fèi', + '剔' => ' tī', + '剓' => ' lí', + '剒' => ' cuò', + '剑' => ' jiàn', + '剏' => ' chuàng', + '剄' => ' jǐng', + '剎' => ' shā', + '前' => ' qián', + '剌' => ' lá', + '剋' => ' kè', + '削' => ' xuē', + '剉' => ' cuò', + '剈' => ' yuān', + '則' => ' zé', + '剆' => ' luǒ', + '剅' => ' lóu', + '刪' => ' shān', + '刨' => ' páo', + '凵' => ' qiǎn', + '刁' => ' diāo', + '刋' => ' qiàn', + '刊' => ' kān', + '刉' => ' jī', + '刈' => ' yì', + '切' => ' qiè', + '分' => ' fēn', + '刅' => ' chuāng', + '刄' => ' rèn', + '刃' => ' rèn', + '刂' => ' dāo', + '刀' => ' dāo', + '刍' => ' chú', + '凿' => ' záo', + '凾' => ' hán', + '函' => ' hán', + '凼' => ' dàng', + '击' => ' jī', + '出' => ' chū', + '凹' => ' āo', + '凸' => ' tū', + '凷' => ' kuài', + '凶' => ' xiōng', + '刌' => ' cǔn', + '刎' => ' wěn', + '刧' => ' jié', + '刜' => ' fú', + '刦' => ' jié', + '別' => ' bié', + '判' => ' pàn', + '刣' => ' zhōng', + '刢' => ' líng', + '刡' => ' mǐn', + '删' => ' shān', + '刟' => ' jū', + '刞' => ' qù', + '初' => ' chū', + '创' => ' chuàng', + '刏' => ' jī', + '刚' => ' gāng', + '则' => ' zé', + '刘' => ' liú', + '列' => ' liè', + '刖' => ' yuè', + '刕' => ' lí', + '刔' => ' jué', + '刓' => ' wán', + '划' => ' huà', + '刑' => ' xíng', + '刐' => ' dǎn', + '匫' => ' hū', + '匭' => ' guǐ', + '哌' => ' pài', + '吿' => ' gào', + '呉' => ' wú', + '呈' => ' chéng', + '呇' => ' qǐ', + '呆' => ' dāi', + '呅' => ' méi', + '呄' => ' gé', + '呃' => ' è', + '呂' => ' lǚ', + '呁' => ' jùn', + '呀' => ' ya', + '吾' => ' wú', + '呋' => ' fū', + '吽' => ' hōng', + '吼' => ' hǒu', + '吻' => ' wěn', + '吺' => ' dōu', + '吹' => ' chuī', + '吸' => ' xī', + '吷' => ' xuè', + '吶' => ' nà', + '吵' => ' chǎo', + '吴' => ' wú', + '告' => ' gào', + '呌' => ' jiào', + '吲' => ' yǐn', + '呙' => ' guō', + '呣' => ' ḿ', + '呢' => ' ne', + '呡' => ' wěn', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/data/words_5 b/lib/vendor/overtrue/pinyin/data/words_5 new file mode 100644 index 0000000000..880304d818 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/data/words_5 @@ -0,0 +1,2055 @@ + ' pěn', + '呟' => ' juǎn', + '呞' => ' shī', + '呝' => ' è', + '呜' => ' wū', + '呛' => ' qiāng', + '呚' => ' wen', + '员' => ' yuán', + '呍' => ' hōng', + '呗' => ' bei', + '呖' => ' lì', + '呕' => ' ǒu', + '呔' => ' dāi', + '呓' => ' yì', + '呒' => ' fǔ', + '呑' => ' tūn', + '呐' => ' nà', + '呏' => ' shēng', + '呎' => ' chǐ', + '吳' => ' wú', + '吱' => ' zhī', + '呥' => ' rán', + '吋' => ' cùn', + '吕' => ' lǚ', + '吔' => ' yě', + '吓' => ' xià', + '吒' => ' zhā', + '向' => ' xiàng', + '吐' => ' tǔ', + '吏' => ' lì', + '后' => ' hòu', + '名' => ' míng', + '同' => ' tóng', + '吊' => ' diào', + '吗' => ' ma', + '吉' => ' jí', + '合' => ' hé', + '吇' => ' zǐ', + '吆' => ' yāo', + '吅' => ' xuān', + '各' => ' gè', + '吃' => ' chī', + '吂' => ' máng', + '吁' => ' xū', + '吀' => ' miē', + '吖' => ' yā', + '吘' => ' ǒu', + '吰' => ' hóng', + '吥' => ' bù', + '启' => ' qǐ', + '吮' => ' shǔn', + '吭' => ' kēng', + '听' => ' tīng', + '含' => ' hán', + '吪' => ' é', + '吩' => ' fēn', + '吨' => ' dūn', + '吧' => ' ba', + '否' => ' fǒu', + '吤' => ' jiè', + '吙' => ' huō', + '吣' => ' qìn', + '吢' => ' qìn', + '吡' => ' bǐ', + '吠' => ' fèi', + '吟' => ' yín', + '吞' => ' tūn', + '吝' => ' lìn', + '吜' => ' chǒu', + '君' => ' jūn', + '吚' => ' yī', + '呤' => ' lìng', + '呦' => ' yōu', + '叾' => ' liǎo', + '咧' => ' liě', + '咱' => ' zán', + '咰' => ' shù', + '咯' => ' gē', + '咮' => ' zhòu', + '咭' => ' jī', + '咬' => ' yǎo', + '咫' => ' zhǐ', + '咪' => ' mī', + '咩' => ' miē', + '咨' => ' zī', + '咦' => ' yí', + '咳' => ' hāi', + '咥' => ' xì', + '咤' => ' zhà', + '咣' => ' guāng', + '咢' => ' è', + '咡' => ' èr', + '咠' => ' qì', + '咟' => ' huò', + '咞' => ' xiàn', + '咝' => ' sī', + '咜' => ' ta', + '咲' => ' xiào', + '咴' => ' huī', + '咚' => ' dōng', + '品' => ' pǐn', + '哋' => ' diè', + '哊' => ' yòu', + '哉' => ' zāi', + '哈' => ' hā', + '哇' => ' wa', + '哆' => ' duō', + '哅' => ' xiōng', + '哄' => ' hōng', + '哃' => ' tóng', + '哂' => ' shěn', + '哀' => ' āi', + '咵' => ' kuǎ', + '咿' => ' yī', + '咾' => ' lǎo', + '咽' => ' yàn', + '咼' => ' guō', + '咻' => ' xiū', + '咺' => ' xuǎn', + '咹' => ' è', + '咸' => ' xián', + '咷' => ' táo', + '咶' => ' huài', + '咛' => ' níng', + '咙' => ' lóng', + '呧' => ' dǐ', + '味' => ' wèi', + '命' => ' mìng', + '呼' => ' hū', + '呻' => ' shēn', + '呺' => ' xiāo', + '呹' => ' yì', + '呸' => ' pēi', + '呷' => ' gā', + '呶' => ' náo', + '呵' => ' ā', + '呴' => ' xǔ', + '呲' => ' cī', + '呿' => ' qù', + '呱' => ' gū', + '呰' => ' zǐ', + '呯' => ' píng', + '呮' => ' qì', + '呭' => ' yì', + '呬' => ' xì', + '呫' => ' tiè', + '呪' => ' zhòu', + '呩' => ' shì', + '周' => ' zhōu', + '呾' => ' dá', + '咀' => ' jǔ', + '咘' => ' bù', + '咍' => ' hāi', + '咗' => ' zuo', + '咖' => ' kā', + '咕' => ' gū', + '咔' => ' kā', + '咓' => ' wǎ', + '咒' => ' zhòu', + '咑' => ' dā', + '咐' => ' fù', + '咏' => ' yǒng', + '咎' => ' jiù', + '和' => ' hé', + '咁' => ' hán', + '咋' => ' zǎ', + '咊' => ' hé', + '咉' => ' yāng', + '咈' => ' fú', + '咇' => ' bié', + '咆' => ' páo', + '咅' => ' pǒu', + '咄' => ' duō', + '咃' => ' tuō', + '咂' => ' zā', + '叿' => ' hōng', + '叽' => ' jī', + '匮' => ' kuì', + '卮' => ' zhī', + '卸' => ' xiè', + '卷' => ' juǎn', + '卶' => ' chǐ', + '卵' => ' luǎn', + '却' => ' què', + '即' => ' jí', + '卲' => ' shào', + '危' => ' wēi', + '印' => ' yìn', + '卯' => ' mǎo', + '卭' => ' qióng', + '卺' => ' jǐn', + '卬' => ' áng', + '卫' => ' wèi', + '卪' => ' jié', + '卩' => ' jié', + '卨' => ' xiè', + '卧' => ' wò', + '卦' => ' guà', + '卥' => ' xī', + '卤' => ' lǔ', + '卣' => ' yǒu', + '卹' => ' xù', + '卻' => ' què', + '卡' => ' kǎ', + '厈' => ' hǎn', + '厒' => ' hé', + '厑' => ' yá', + '厐' => ' páng', + '厏' => ' zhǎ', + '厎' => ' dǐ', + '厍' => ' shè', + '厌' => ' yàn', + '压' => ' yā', + '厊' => ' yǎ', + '厉' => ' lì', + '厇' => ' zhé', + '卼' => ' wù', + '历' => ' lì', + '厅' => ' tīng', + '厄' => ' è', + '厃' => ' wěi', + '厂' => ' chǎng', + '厁' => ' san', + '厀' => ' xī', + '卿' => ' qīng', + '卾' => ' è', + '卽' => ' jí', + '卢' => ' lú', + '占' => ' zhàn', + '厔' => ' zhì', + '区' => ' qū', + '卄' => ' niàn', + '千' => ' qiān', + '卂' => ' xùn', + '十' => ' shí', + '區' => ' qū', + '匿' => ' nì', + '匾' => ' biǎn', + '匽' => ' yǎn', + '匼' => ' kē', + '医' => ' yī', + '匹' => ' pǐ', + '卆' => ' zú', + '匸' => ' xì', + '匷' => ' jué', + '匶' => ' jiù', + '匵' => ' dú', + '匴' => ' suǎn', + '匳' => ' lián', + '匲' => ' lián', + '匱' => ' guì', + '匰' => ' dān', + '匯' => ' huì', + '卅' => ' sà', + '升' => ' shēng', + '卟' => ' bǔ', + '協' => ' xié', + '卞' => ' biàn', + '卝' => ' kuàng', + '卜' => ' bo', + '卛' => ' shuài', + '博' => ' bó', + '卙' => ' jí', + '単' => ' dān', + '南' => ' nán', + '卖' => ' mài', + '单' => ' dān', + '卓' => ' zhuō', + '午' => ' wǔ', + '卒' => ' zú', + '卑' => ' bēi', + '卐' => ' wàn', + '协' => ' xié', + '华' => ' huá', + '卍' => ' wàn', + '卌' => ' xì', + '卋' => ' shì', + '半' => ' bàn', + '卉' => ' huì', + '厓' => ' yá', + '厕' => ' cè', + '叼' => ' diāo', + '受' => ' shòu', + '叡' => ' ruì', + '叠' => ' dié', + '叟' => ' sǒu', + '叞' => ' wèi', + '叝' => ' gào', + '叜' => ' sǒu', + '叛' => ' pàn', + '叚' => ' jiǎ', + '叙' => ' xù', + '变' => ' biàn', + '取' => ' qǔ', + '口' => ' kǒu', + '叕' => ' zhuó', + '叔' => ' shū', + '叓' => ' shì', + '叒' => ' ruò', + '发' => ' fā', + '叐' => ' bá', + '叏' => ' guài', + '収' => ' shōu', + '反' => ' fǎn', + '双' => ' shuāng', + '叢' => ' cóng', + '古' => ' gǔ', + '及' => ' jí', + '叱' => ' chì', + '叻' => ' lè', + '叺' => ' chǐ', + '叹' => ' tàn', + '司' => ' sī', + '号' => ' hào', + '叶' => ' yè', + '叵' => ' pǒ', + '叴' => ' qiú', + '右' => ' yòu', + '史' => ' shǐ', + '台' => ' tái', + '句' => ' jù', + '可' => ' kě', + '叮' => ' dīng', + '叭' => ' bā', + '召' => ' zhào', + '叫' => ' jiào', + '只' => ' zhǐ', + '叩' => ' kòu', + '叨' => ' dāo', + '叧' => ' guǎ', + '另' => ' lìng', + '友' => ' yǒu', + '叉' => ' chā', + '厖' => ' páng', + '厢' => ' xiāng', + '厬' => ' guǐ', + '厫' => ' áo', + '厪' => ' jǐn', + '厩' => ' jiù', + '厨' => ' chú', + '厧' => ' diān', + '厦' => ' shà', + '厥' => ' jué', + '厤' => ' lì', + '厣' => ' yǎn', + '厡' => ' yuán', + '厮' => ' sī', + '厠' => ' cè', + '原' => ' yuán', + '厞' => ' fèi', + '厝' => ' cuò', + '厜' => ' zuī', + '厛' => ' tīng', + '厚' => ' hòu', + '厙' => ' shè', + '厘' => ' lí', + '厗' => ' tí', + '厭' => ' yàn', + '厯' => ' lì', + '又' => ' yòu', + '厽' => ' lěi', + '叇' => ' dài', + '叆' => ' ài', + '叅' => ' cān', + '叄' => ' cān', + '參' => ' cān', + '参' => ' cān', + '叁' => ' sān', + '叀' => ' zhuān', + '县' => ' xiàn', + '厾' => ' dū', + '厼' => ' ěr', + '厰' => ' chǎng', + '去' => ' qù', + '厺' => ' qù', + '厹' => ' róu', + '厸' => ' lín', + '厷' => ' gōng', + '厶' => ' sī', + '厵' => ' yuán', + '厴' => ' yǎn', + '厳' => ' yán', + '厲' => ' lì', + '厱' => ' lán', + '堎' => ' lèng', + '堐' => ' yá', + '庑' => ' wǔ', + '屣' => ' xǐ', + '屭' => ' xì', + '屬' => ' shǔ', + '屫' => ' jué', + '屪' => ' liáo', + '屩' => ' juē', + '屨' => ' jù', + '屧' => ' xiè', + '屦' => ' jù', + '履' => ' lǚ', + '層' => ' céng', + '屢' => ' lǚ', + '屯' => ' tún', + '屡' => ' lǚ', + '屠' => ' tú', + '屟' => ' xiè', + '属' => ' shǔ', + '屝' => ' fèi', + '屜' => ' tì', + '屛' => ' píng', + '屚' => ' lòu', + '屙' => ' ē', + '屘' => ' mǎn', + '屮' => ' chè', + '屰' => ' nì', + '屖' => ' xī', + '屽' => ' hàn', + '岇' => ' áng', + '岆' => ' yǎo', + '岅' => ' bǎn', + '岄' => ' yuè', + '岃' => ' rèn', + '岂' => ' qǐ', + '岁' => ' suì', + '岀' => ' chū', + '屿' => ' yǔ', + '屾' => ' shēn', + '屼' => ' wù', + '山' => ' shān', + '屻' => ' rèn', + '屺' => ' qǐ', + '屹' => ' yì', + '屸' => ' lóng', + '屷' => ' hui', + '屶' => ' dao', + '屵' => ' è', + '屴' => ' lì', + '屳' => ' xiān', + '屲' => ' wa', + '屗' => ' wěi', + '展' => ' zhǎn', + '岉' => ' wù', + '尯' => ' kuì', + '尹' => ' yǐn', + '尸' => ' shī', + '尷' => ' gān', + '尶' => ' gān', + '尵' => ' tuí', + '尴' => ' gān', + '尳' => ' gǔ', + '尲' => ' gān', + '就' => ' jiù', + '尰' => ' zhǒng', + '尮' => ' duò', + '尻' => ' kāo', + '尭' => ' yáo', + '尬' => ' gà', + '尫' => ' wāng', + '尪' => ' wāng', + '尩' => ' wāng', + '尨' => ' máng', + '尧' => ' yáo', + '尦' => ' liào', + '尥' => ' liào', + '尤' => ' yóu', + '尺' => ' chǐ', + '尼' => ' ní', + '屔' => ' ní', + '屉' => ' tì', + '屓' => ' xiè', + '屒' => ' zhěn', + '屑' => ' xiè', + '屐' => ' jī', + '屏' => ' píng', + '屎' => ' shǐ', + '屍' => ' shī', + '屌' => ' diǎo', + '屋' => ' wū', + '届' => ' jiè', + '屈' => ' qū', + '尽' => ' jǐn', + '屇' => ' tián', + '屆' => ' jiè', + '居' => ' jū', + '屄' => ' bī', + '屃' => ' xì', + '层' => ' céng', + '屁' => ' pì', + '局' => ' jú', + '尿' => ' niào', + '尾' => ' wěi', + '岈' => ' yá', + '岊' => ' jié', + '尢' => ' yóu', + '峋' => ' xún', + '峕' => ' shí', + '峔' => ' mǔ', + '峓' => ' yí', + '峒' => ' dòng', + '峑' => ' quān', + '峐' => ' gāi', + '峏' => ' ér', + '峎' => ' ěn', + '峍' => ' lù', + '峌' => ' dié', + '峊' => ' fù', + '峗' => ' wéi', + '峉' => ' è', + '峈' => ' luò', + '峇' => ' bā', + '峆' => ' hé', + '峅' => ' bian', + '峄' => ' yì', + '峃' => ' xué', + '峂' => ' tóng', + '峁' => ' mǎo', + '峀' => ' xiù', + '峖' => ' ān', + '峘' => ' huán', + '岾' => ' hàn', + '峥' => ' zhēng', + '峯' => ' fēng', + '峮' => ' qūn', + '峭' => ' qiào', + '峬' => ' bū', + '峫' => ' xié', + '峪' => ' yù', + '峩' => ' é', + '峨' => ' é', + '峧' => ' jiāo', + '峦' => ' luán', + '峤' => ' jiào', + '峙' => ' zhì', + '峣' => ' yáo', + '峢' => ' lǐ', + '峡' => ' xiá', + '峠' => ' gu', + '峟' => ' yòu', + '峞' => ' wéi', + '峝' => ' tóng', + '峜' => ' jì', + '峛' => ' lǐ', + '峚' => ' mì', + '岿' => ' kuī', + '岽' => ' dōng', + '岋' => ' è', + '岗' => ' gǎng', + '岡' => ' gāng', + '岠' => ' jù', + '岟' => ' yǎng', + '岞' => ' zuò', + '岝' => ' zuò', + '岜' => ' bā', + '岛' => ' dǎo', + '岚' => ' lán', + '岙' => ' ào', + '岘' => ' xiàn', + '岖' => ' qū', + '岣' => ' gǒu', + '岕' => ' jiè', + '岔' => ' chà', + '岓' => ' qí', + '岒' => ' qián', + '岑' => ' cén', + '岐' => ' qí', + '岏' => ' wán', + '岎' => ' fén', + '岍' => ' qiān', + '岌' => ' jí', + '岢' => ' kě', + '岤' => ' xué', + '岼' => ' ping', + '岱' => ' dài', + '岻' => ' chí', + '岺' => ' líng', + '岹' => ' tiáo', + '岸' => ' àn', + '岷' => ' mín', + '岶' => ' pò', + '岵' => ' hù', + '岴' => ' qū', + '岳' => ' yuè', + '岲' => ' kuàng', + '岰' => ' ào', + '岥' => ' pō', + '岯' => ' pí', + '岮' => ' tuó', + '岭' => ' lǐng', + '岬' => ' jiǎ', + '岫' => ' xiù', + '岪' => ' fú', + '岩' => ' yán', + '岨' => ' qū', + '岧' => ' tiáo', + '岦' => ' lì', + '尣' => ' wāng', + '尡' => ' kun', + '峱' => ' náo', + '宓' => ' mì', + '宝' => ' bǎo', + '宜' => ' yí', + '宛' => ' wǎn', + '定' => ' dìng', + '宙' => ' zhòu', + '官' => ' guān', + '宗' => ' zōng', + '宖' => ' hóng', + '宕' => ' dàng', + '宔' => ' zhǔ', + '宒' => ' zhūn', + '実' => ' shí', + '宑' => ' jǐng', + '宐' => ' yí', + '宏' => ' hóng', + '宎' => ' yǎo', + '宍' => ' ròu', + '完' => ' wán', + '宋' => ' sòng', + '宊' => ' tū', + '安' => ' ān', + '守' => ' shǒu', + '实' => ' shí', + '宠' => ' chǒng', + '宆' => ' qióng', + '宭' => ' qún', + '宷' => ' shěn', + '家' => ' jiā', + '宵' => ' xiāo', + '宴' => ' yàn', + '害' => ' hài', + '宲' => ' bǎo', + '宱' => ' zhà', + '宰' => ' zǎi', + '宯' => ' xiāo', + '宮' => ' gōng', + '宬' => ' chéng', + '审' => ' shěn', + '宫' => ' gōng', + '宪' => ' xiàn', + '宩' => ' shǐ', + '宨' => ' tiǎo', + '宧' => ' yí', + '宦' => ' huàn', + '宥' => ' yòu', + '室' => ' shì', + '宣' => ' xuān', + '客' => ' kè', + '宇' => ' yǔ', + '宅' => ' zhái', + '容' => ' róng', + '孟' => ' mèng', + '孩' => ' hái', + '孨' => ' zhuǎn', + '孧' => ' you', + '学' => ' xué', + '孥' => ' nú', + '孤' => ' gū', + '季' => ' jì', + '孢' => ' bāo', + '孡' => ' tāi', + '孠' => ' sì', + '孞' => ' xìn', + '孫' => ' sūn', + '孝' => ' xiào', + '孜' => ' zī', + '孛' => ' bèi', + '孚' => ' fú', + '孙' => ' sūn', + '存' => ' cún', + '字' => ' zì', + '孖' => ' mā', + '孕' => ' yùn', + '孔' => ' kǒng', + '孪' => ' luán', + '孬' => ' nāo', + '宄' => ' guǐ', + '孹' => ' bò', + '它' => ' tā', + '宂' => ' rǒng', + '宁' => ' níng', + '宀' => ' mián', + '孿' => ' luán', + '孾' => ' yīng', + '孽' => ' niè', + '孼' => ' niè', + '孻' => ' nái', + '孺' => ' rú', + '學' => ' xué', + '孭' => ' miē', + '孷' => ' lí', + '孶' => ' zī', + '孵' => ' fū', + '孴' => ' nǐ', + '孳' => ' zī', + '孲' => ' yā', + '孱' => ' càn', + '孰' => ' shú', + '孯' => ' qiān', + '孮' => ' cóng', + '宸' => ' chén', + '宺' => ' huǎng', + '尠' => ' xiǎn', + '寻' => ' xún', + '尅' => ' kè', + '射' => ' shè', + '尃' => ' fū', + '専' => ' zhuān', + '封' => ' fēng', + '尀' => ' pǒ', + '寿' => ' shòu', + '対' => ' duì', + '寽' => ' lǜ', + '导' => ' dǎo', + '寺' => ' sì', + '將' => ' jiāng', + '对' => ' duì', + '寸' => ' cùn', + '寷' => ' fēng', + '寶' => ' bǎo', + '寵' => ' chǒng', + '寴' => ' qīn', + '寳' => ' bǎo', + '寲' => ' yí', + '寱' => ' yì', + '寰' => ' huán', + '将' => ' jiāng', + '專' => ' zhuān', + '寮' => ' liáo', + '尕' => ' gǎ', + '尟' => ' xiǎn', + '尞' => ' liào', + '尝' => ' cháng', + '尜' => ' gá', + '尛' => ' mo', + '尚' => ' shàng', + '尙' => ' shàng', + '尘' => ' chén', + '尗' => ' shū', + '尖' => ' jiān', + '尔' => ' ěr', + '尉' => ' wèi', + '尓' => ' ěr', + '尒' => ' ěr', + '少' => ' shǎo', + '尐' => ' jié', + '小' => ' xiǎo', + '導' => ' dǎo', + '對' => ' duì', + '尌' => ' shù', + '尋' => ' xún', + '尊' => ' zūn', + '寯' => ' jùn', + '寭' => ' huì', + '宻' => ' mì', + '寇' => ' kòu', + '寑' => ' qǐn', + '寐' => ' mèi', + '寏' => ' huán', + '寎' => ' bìng', + '寍' => ' níng', + '富' => ' fù', + '寋' => ' jiàn', + '寊' => ' zhēn', + '寉' => ' què', + '寈' => ' qīng', + '密' => ' mì', + '寓' => ' yù', + '寅' => ' yín', + '寄' => ' jì', + '寃' => ' yuān', + '寂' => ' jì', + '寁' => ' zǎn', + '寀' => ' cǎi', + '宿' => ' sù', + '宾' => ' bīn', + '宽' => ' kuān', + '宼' => ' kòu', + '寒' => ' hán', + '寔' => ' shí', + '寬' => ' kuān', + '寡' => ' guǎ', + '寫' => ' xiě', + '寪' => ' wěi', + '審' => ' shěn', + '寨' => ' zhài', + '寧' => ' níng', + '實' => ' shí', + '寥' => ' liáo', + '寤' => ' wù', + '寣' => ' hū', + '寢' => ' qǐn', + '寠' => ' jù', + '寕' => ' níng', + '察' => ' chá', + '寞' => ' mò', + '寝' => ' qǐn', + '寜' => ' níng', + '寛' => ' kuān', + '寚' => ' bǎo', + '寙' => ' yǔ', + '寘' => ' zhì', + '寗' => ' níng', + '寖' => ' jìn', + '峰' => ' fēng', + '峲' => ' lǐ', + '孒' => ' jué', + '帄' => ' dīng', + '帎' => ' dàn', + '帍' => ' hù', + '希' => ' xī', + '帋' => ' zhǐ', + '帊' => ' pà', + '帉' => ' fēn', + '师' => ' shī', + '帇' => ' niè', + '帆' => ' fān', + '帅' => ' shuài', + '布' => ' bù', + '帐' => ' zhàng', + '市' => ' shì', + '币' => ' bì', + '帀' => ' zā', + '巿' => ' fú', + '巾' => ' jīn', + '巽' => ' xùn', + '巼' => ' bā', + '巻' => ' juàn', + '巺' => ' xùn', + '巹' => ' jǐn', + '帏' => ' wéi', + '帑' => ' tǎng', + '巷' => ' xiàng', + '帞' => ' mò', + '帨' => ' shuì', + '帧' => ' zhèng', + '带' => ' dài', + '帥' => ' shuài', + '帤' => ' rú', + '帣' => ' juǎn', + '帢' => ' qià', + '帡' => ' píng', + '帠' => ' yì', + '帟' => ' yì', + '帝' => ' dì', + '帒' => ' dài', + '帜' => ' zhì', + '帛' => ' bó', + '帚' => ' zhǒu', + '帙' => ' zhì', + '帘' => ' lián', + '帗' => ' bō', + '帖' => ' tiē', + '帕' => ' pà', + '帔' => ' pèi', + '帓' => ' mò', + '巸' => ' yí', + '巶' => ' zhāo', + '帪' => ' zhēn', + '巐' => ' chǎo', + '巚' => ' yǎn', + '巙' => ' kuí', + '巘' => ' yǎn', + '巗' => ' yán', + '巖' => ' yán', + '巕' => ' nie', + '巔' => ' diān', + '巓' => ' diān', + '巒' => ' luán', + '巑' => ' cuán', + '巏' => ' quán', + '巜' => ' kuài', + '巎' => ' náo', + '巍' => ' wēi', + '巌' => ' yán', + '巋' => ' kuī', + '巊' => ' yǐng', + '巉' => ' chán', + '巈' => ' jú', + '巇' => ' xī', + '巆' => ' róng', + '巅' => ' diān', + '巛' => ' chuān', + '川' => ' chuān', + '巵' => ' zhī', + '巪' => ' jù', + '巴' => ' bā', + '巳' => ' sì', + '已' => ' yǐ', + '己' => ' jǐ', + '巰' => ' qiú', + '巯' => ' qiú', + '差' => ' chà', + '巭' => ' pu', + '巬' => ' pu', + '巫' => ' wū', + '巩' => ' gǒng', + '州' => ' zhōu', + '巨' => ' jù', + '巧' => ' qiǎo', + '左' => ' zuǒ', + '工' => ' gōng', + '巤' => ' liè', + '巣' => ' cháo', + '巢' => ' cháo', + '巡' => ' xún', + '巠' => ' jīng', + '巟' => ' huāng', + '帩' => ' qiào', + '師' => ' shī', + '巃' => ' lóng', + '幬' => ' chóu', + '并' => ' bìng', + '幵' => ' jiān', + '年' => ' nián', + '平' => ' píng', + '干' => ' gàn', + '幱' => ' lán', + '幰' => ' xiǎn', + '幯' => ' jié', + '幮' => ' chú', + '幭' => ' miè', + '幫' => ' bāng', + '幸' => ' xìng', + '幪' => ' méng', + '幩' => ' fén', + '幨' => ' chān', + '幧' => ' qiāo', + '幦' => ' mì', + '幥' => ' zhang', + '幤' => ' bi', + '幣' => ' bì', + '幢' => ' chuáng', + '幡' => ' fān', + '幷' => ' bìng', + '幹' => ' gàn', + '幟' => ' zhì', + '庆' => ' qìng', + '庐' => ' lú', + '序' => ' xù', + '庎' => ' jiè', + '庍' => ' bài', + '庌' => ' yǎ', + '庋' => ' guǐ', + '床' => ' chuáng', + '庉' => ' dùn', + '庈' => ' qín', + '庇' => ' bì', + '庅' => ' mó', + '幺' => ' yāo', + '庄' => ' zhuāng', + '広' => ' guǎng', + '庂' => ' zè', + '庁' => ' tīng', + '庀' => ' pǐ', + '广' => ' guǎng', + '幾' => ' jǐ', + '幽' => ' yōu', + '幼' => ' yòu', + '幻' => ' huàn', + '幠' => ' hū', + '幞' => ' fú', + '帬' => ' qún', + '常' => ' cháng', + '幂' => ' mì', + '幁' => ' xū', + '幀' => ' zhèng', + '帿' => ' hóu', + '帾' => ' dǔ', + '帽' => ' mào', + '帼' => ' guó', + '帻' => ' zé', + '帺' => ' qí', + '帹' => ' shà', + '帷' => ' wéi', + '幄' => ' wò', + '帶' => ' dài', + '帵' => ' wān', + '帴' => ' sàn', + '帳' => ' zhàng', + '帲' => ' píng', + '帱' => ' chóu', + '帰' => ' guī', + '帯' => ' dài', + '帮' => ' bāng', + '席' => ' xí', + '幃' => ' wéi', + '幅' => ' fú', + '幝' => ' chǎn', + '幒' => ' zhōng', + '幜' => ' jǐng', + '幛' => ' zhàng', + '幚' => ' bāng', + '幙' => ' mù', + '幘' => ' zé', + '幗' => ' guó', + '幖' => ' biāo', + '幕' => ' mù', + '幔' => ' màn', + '幓' => ' shān', + '幑' => ' huī', + '幆' => ' yì', + '幐' => ' téng', + '幏' => ' jià', + '幎' => ' mì', + '幍' => ' tāo', + '幌' => ' huǎng', + '幋' => ' pán', + '幊' => ' gōng', + '幉' => ' die', + '幈' => ' píng', + '幇' => ' bāng', + '巄' => ' lóng', + '巂' => ' guī', + '峳' => ' yóu', + '崳' => ' yú', + '崽' => ' zǎi', + '崼' => ' shì', + '崻' => ' zhì', + '崺' => ' yǐ', + '崹' => ' tí', + '崸' => ' yáng', + '崷' => ' qiú', + '崶' => ' fēng', + '崵' => ' yáng', + '崴' => ' wǎi', + '崲' => ' huáng', + '崿' => ' è', + '崱' => ' zè', + '崰' => ' zi', + '崯' => ' yín', + '崮' => ' gù', + '崭' => ' zhǎn', + '崬' => ' dōng', + '崫' => ' kū', + '崪' => ' zú', + '崩' => ' bēng', + '崨' => ' jié', + '崾' => ' yǎo', + '嵀' => ' zhù', + '崦' => ' yān', + '嵍' => ' wù', + '嵗' => ' suì', + '嵖' => ' chá', + '嵕' => ' zōng', + '嵔' => ' wěi', + '嵓' => ' yán', + '嵒' => ' yán', + '嵑' => ' kě', + '嵐' => ' lán', + '嵏' => ' zōng', + '嵎' => ' yú', + '嵌' => ' qiàn', + '嵁' => ' kān', + '嵋' => ' méi', + '嵊' => ' shèng', + '嵉' => ' tíng', + '嵈' => ' huàn', + '嵇' => ' jī', + '嵆' => ' jī', + '嵅' => ' hán', + '嵄' => ' měi', + '嵃' => ' yǎn', + '嵂' => ' lǜ', + '崧' => ' sōng', + '崥' => ' pí', + '嵙' => ' ke', + '峿' => ' yǔ', + '崉' => ' tà', + '崈' => ' chóng', + '崇' => ' chóng', + '崆' => ' kōng', + '崅' => ' què', + '崄' => ' xiǎn', + '崃' => ' lái', + '崂' => ' láo', + '崁' => ' kàn', + '崀' => ' làng', + '峾' => ' yín', + '崋' => ' huà', + '峽' => ' xiá', + '峼' => ' hào', + '峻' => ' jùn', + '峺' => ' gěng', + '峹' => ' tú', + '峸' => ' chéng', + '峷' => ' shēn', + '島' => ' dǎo', + '峵' => ' hóng', + '峴' => ' xiàn', + '崊' => ' lín', + '崌' => ' jū', + '崤' => ' xiáo', + '崙' => ' lún', + '崣' => ' wěi', + '崢' => ' zhēng', + '崡' => ' hán', + '崠' => ' dōng', + '崟' => ' yín', + '崞' => ' guō', + '崝' => ' zhēng', + '崜' => ' duō', + '崛' => ' jué', + '崚' => ' léng', + '崘' => ' lún', + '崍' => ' lái', + '崗' => ' gǎng', + '崖' => ' yá', + '崕' => ' yá', + '崔' => ' cuī', + '崓' => ' gù', + '崒' => ' zú', + '崑' => ' kūn', + '崐' => ' kūn', + '崏' => ' mín', + '崎' => ' qí', + '嵘' => ' róng', + '嵚' => ' qīn', + '巁' => ' lì', + '嶜' => ' jīn', + '嶦' => ' zhān', + '嶥' => ' jué', + '嶤' => ' yáo', + '嶣' => ' jiāo', + '嶢' => ' yáo', + '嶡' => ' guì', + '嶠' => ' jiào', + '嶟' => ' zūn', + '嶞' => ' duò', + '嶝' => ' dèng', + '嶛' => ' liáo', + '嶨' => ' xué', + '嶚' => ' liáo', + '嶙' => ' lín', + '嶘' => ' zhàn', + '嶗' => ' láo', + '嶖' => ' yǎn', + '嶕' => ' jiāo', + '嶔' => ' qīn', + '嶓' => ' bō', + '嶒' => ' céng', + '嶑' => ' xiàng', + '嶧' => ' yì', + '嶩' => ' náo', + '嶏' => ' pèi', + '嶶' => ' wei', + '巀' => ' jié', + '嶿' => ' ru', + '嶾' => ' yǐn', + '嶽' => ' yuè', + '嶼' => ' yǔ', + '嶻' => ' zá', + '嶺' => ' lǐng', + '嶹' => ' dǎo', + '嶸' => ' róng', + '嶷' => ' yí', + '嶵' => ' zuǐ', + '嶪' => ' yè', + '嶴' => ' ào', + '嶳' => ' dì', + '嶲' => ' xī', + '嶱' => ' kě', + '嶰' => ' xiè', + '嶯' => ' jí', + '嶮' => ' xiǎn', + '嶭' => ' niè', + '嶬' => ' yí', + '嶫' => ' yè', + '嶐' => ' lóng', + '嶎' => ' yù', + '嵛' => ' yú', + '嵧' => ' liú', + '嵱' => ' yǒng', + '嵰' => ' qiǎn', + '嵯' => ' cuó', + '嵮' => ' diān', + '嵭' => ' bēng', + '嵬' => ' wéi', + '嵫' => ' zī', + '嵪' => ' qiāo', + '嵩' => ' sōng', + '嵨' => ' wù', + '嵦' => ' kǎi', + '嵳' => ' cuó', + '嵥' => ' jié', + '嵤' => ' róng', + '嵣' => ' dàng', + '嵢' => ' cāng', + '嵡' => ' wěng', + '嵠' => ' xī', + '嵟' => ' duī', + '嵞' => ' tú', + '嵝' => ' lǒu', + '嵜' => ' ti', + '嵲' => ' niè', + '嵴' => ' jǐ', + '嶍' => ' xí', + '嶂' => ' zhàng', + '嶌' => ' dǎo', + '嶋' => ' dǎo', + '嶊' => ' zuǐ', + '嶉' => ' cuī', + '嶈' => ' qiāng', + '嶇' => ' qū', + '嶆' => ' cáo', + '嶅' => ' áo', + '嶄' => ' zhǎn', + '嶃' => ' zhǎn', + '嶁' => ' lǒu', + '嵵' => ' shi', + '嶀' => ' tū', + '嵿' => ' dǐng', + '嵾' => ' cēn', + '嵽' => ' dié', + '嵼' => ' chǎn', + '嵻' => ' kāng', + '嵺' => ' liáo', + '嵹' => ' jiàng', + '嵸' => ' zōng', + '嵷' => ' sǒng', + '嵶' => ' ruo', + '孓' => ' jué', + '孑' => ' jié', + '堑' => ' qiàn', + '夢' => ' mèng', + '夬' => ' guài', + '夫' => ' fū', + '太' => ' tài', + '天' => ' tiān', + '夨' => ' zè', + '大' => ' dà', + '夦' => ' chěn', + '夥' => ' huǒ', + '夤' => ' yín', + '夣' => ' mèng', + '夡' => ' qì', + '央' => ' yāng', + '夠' => ' gòu', + '够' => ' gòu', + '夞' => ' wài', + '夝' => ' qíng', + '夜' => ' yè', + '夛' => ' duō', + '多' => ' duō', + '夙' => ' sù', + '夘' => ' mǎo', + '夗' => ' yuàn', + '夭' => ' yāo', + '夯' => ' hāng', + '夕' => ' xī', + '夼' => ' kuǎng', + '奆' => ' juàn', + '奅' => ' pào', + '奄' => ' yǎn', + '奃' => ' dī', + '奂' => ' huàn', + '奁' => ' lián', + '奀' => ' ēn', + '夿' => ' bā', + '夾' => ' jiā', + '夽' => ' yǔn', + '夻' => ' huà', + '夰' => ' gǎo', + '夺' => ' duó', + '夹' => ' jiā', + '夸' => ' kuā', + '夷' => ' yí', + '夶' => ' bǐ', + '夵' => ' yǎn', + '头' => ' tóu', + '夳' => ' tài', + '夲' => ' tāo', + '失' => ' shī', + '外' => ' wài', + '夔' => ' kuí', + '奈' => ' nài', + '壮' => ' zhuàng', + '壸' => ' kǔn', + '壷' => ' hú', + '壶' => ' hú', + '壵' => ' zhuàng', + '壴' => ' zhù', + '壳' => ' ké', + '売' => ' mài', + '壱' => ' yī', + '声' => ' shēng', + '壯' => ' zhuàng', + '壭' => ' san', + '壺' => ' hú', + '壬' => ' rén', + '士' => ' shì', + '壪' => ' wān', + '壩' => ' bà', + '壨' => ' léi', + '壧' => ' yán', + '壦' => ' xūn', + '壥' => ' chan', + '壤' => ' rǎng', + '壣' => ' lín', + '壹' => ' yī', + '壻' => ' xù', + '夓' => ' xià', + '夈' => ' zhai', + '夒' => ' náo', + '夑' => ' xie', + '夐' => ' xiòng', + '夏' => ' xià', + '夎' => ' cuò', + '复' => ' fù', + '夌' => ' líng', + '夋' => ' qūn', + '夊' => ' suī', + '変' => ' biàn', + '备' => ' bèi', + '壼' => ' kǔn', + '夆' => ' féng', + '夅' => ' jiàng', + '处' => ' chù', + '夃' => ' gǔ', + '夂' => ' zhǐ', + '夁' => ' yī', + '夀' => ' shòu', + '壿' => ' zūn', + '壾' => ' mǎng', + '壽' => ' shòu', + '奇' => ' qí', + '奉' => ' fèng', + '壡' => ' ruì', + '妊' => ' rèn', + '妔' => ' kēng', + '妓' => ' jì', + '妒' => ' dù', + '妑' => ' pā', + '妐' => ' zhōng', + '妏' => ' wèn', + '妎' => ' hài', + '妍' => ' yán', + '妌' => ' jìng', + '妋' => ' fū', + '妉' => ' dān', + '妖' => ' yāo', + '妈' => ' mā', + '妇' => ' fù', + '妆' => ' zhuāng', + '妅' => ' hóng', + '妄' => ' wàng', + '妃' => ' fēi', + '如' => ' rú', + '妁' => ' shuò', + '妀' => ' jǐ', + '奿' => ' fàn', + '妕' => ' zhòng', + '妗' => ' jìn', + '好' => ' hǎo', + '妤' => ' yú', + '妮' => ' nī', + '妭' => ' bá', + '妬' => ' dù', + '妫' => ' guī', + '妪' => ' yù', + '妩' => ' wǔ', + '妨' => ' fáng', + '妧' => ' wàn', + '妦' => ' fēng', + '妥' => ' tuǒ', + '妣' => ' bǐ', + '妘' => ' yún', + '妢' => ' fén', + '妡' => ' xīn', + '妠' => ' nà', + '妟' => ' yàn', + '妞' => ' niū', + '妝' => ' zhuāng', + '妜' => ' yuè', + '妛' => ' chi', + '妚' => ' fǒu', + '妙' => ' miào', + '奾' => ' xiān', + '奼' => ' chà', + '奊' => ' xié', + '奖' => ' jiǎng', + '奠' => ' diàn', + '奟' => ' bēng', + '奞' => ' xùn', + '奝' => ' diāo', + '奜' => ' fěi', + '奛' => ' huǎng', + '奚' => ' xī', + '奙' => ' běn', + '奘' => ' zàng', + '套' => ' tào', + '奕' => ' yì', + '奢' => ' shē', + '奔' => ' bēn', + '奓' => ' zhā', + '奒' => ' kāi', + '契' => ' qì', + '奐' => ' huàn', + '奏' => ' zòu', + '奎' => ' kuí', + '奍' => ' yang', + '奌' => ' diǎn', + '奋' => ' fèn', + '奡' => ' ào', + '奣' => ' wěng', + '奻' => ' nuán', + '奰' => ' bì', + '奺' => ' jiǔ', + '她' => ' tā', + '奸' => ' jiān', + '奷' => ' qiān', + '奶' => ' nǎi', + '奵' => ' dǐng', + '奴' => ' nú', + '女' => ' nǚ', + '奲' => ' duǒ', + '奱' => ' luán', + '奯' => ' huò', + '奤' => ' hǎ', + '奮' => ' fèn', + '奭' => ' shì', + '奬' => ' jiǎng', + '奫' => ' yūn', + '奪' => ' duó', + '奩' => ' lián', + '奨' => ' jiǎng', + '奧' => ' ào', + '奦' => ' wù', + '奥' => ' ào', + '壢' => ' lì', + '壠' => ' lǒng', + '妰' => ' zhuó', + '塑' => ' sù', + '塛' => ' lì', + '塚' => ' zhǒng', + '塙' => ' què', + '塘' => ' táng', + '塗' => ' tú', + '塖' => ' chéng', + '塕' => ' wěng', + '塔' => ' tǎ', + '塓' => ' mì', + '塒' => ' shí', + '塐' => ' sù', + '塝' => ' bàng', + '塏' => ' kǎi', + '塎' => ' yǒng', + '塍' => ' chéng', + '塌' => ' tā', + '塋' => ' yíng', + '塊' => ' kuài', + '塉' => ' jí', + '塈' => ' jì', + '塇' => ' xuān', + '塆' => ' wān', + '塜' => ' zhǒng', + '塞' => ' sāi', + '塄' => ' léng', + '填' => ' tián', + '塵' => ' chén', + '塴' => ' bèng', + '塳' => ' péng', + '塲' => ' cháng', + '塱' => ' lǎng', + '塰' => ' hai', + '塯' => ' liù', + '塮' => ' xiè', + '塭' => ' wēn', + '塬' => ' yuán', + '塪' => ' kǎn', + '塟' => ' zàng', + '塩' => ' yán', + '塨' => ' gōng', + '塧' => ' ài', + '塦' => ' zhèn', + '塥' => ' gé', + '塤' => ' xūn', + '塣' => ' zhèng', + '塢' => ' wù', + '塡' => ' tián', + '塠' => ' duī', + '塅' => ' duàn', + '塃' => ' huāng', + '塷' => ' lǔ', + '堝' => ' guō', + '堧' => ' ruán', + '堦' => ' jiē', + '堥' => ' máo', + '堤' => ' dī', + '堣' => ' yú', + '堢' => ' bǎo', + '堡' => ' bǎo', + '堠' => ' hòu', + '堟' => ' zhuàn', + '堞' => ' dié', + '堜' => ' liàn', + '堩' => ' gèng', + '堛' => ' bì', + '堚' => ' hún', + '堙' => ' yīn', + '堘' => ' chéng', + '堗' => ' tū', + '堖' => ' nǎo', + '堕' => ' duò', + '堔' => ' shen', + '堓' => ' àn', + '堒' => ' kun', + '堨' => ' yè', + '堪' => ' kān', + '塂' => ' xiàng', + '堷' => ' yìn', + '塁' => ' lei', + '塀' => ' ping', + '堿' => ' jiǎn', + '堾' => ' chūn', + '堽' => ' gāng', + '堼' => ' hèng', + '堻' => ' jīn', + '堺' => ' jiè', + '堹' => ' zhòng', + '堸' => ' féng', + '堶' => ' tuó', + '堫' => ' zōng', + '堵' => ' dǔ', + '場' => ' chǎng', + '堳' => ' méi', + '堲' => ' cí', + '報' => ' bào', + '堰' => ' yàn', + '堯' => ' yáo', + '堮' => ' è', + '堭' => ' huáng', + '堬' => ' yú', + '塶' => ' lù', + '塸' => ' ōu', + '壟' => ' lǒng', + '墺' => ' ào', + '壄' => ' yě', + '壃' => ' jiāng', + '壂' => ' diàn', + '壁' => ' bì', + '壀' => ' pí', + '墿' => ' yì', + '墾' => ' kěn', + '墽' => ' qiāo', + '墼' => ' jī', + '墻' => ' qiáng', + '墹' => ' jian', + '壆' => ' xué', + '墸' => ' zhu', + '墷' => ' yè', + '墶' => ' da', + '墵' => ' tán', + '墴' => ' huáng', + '墳' => ' fén', + '墲' => ' mú', + '墱' => ' dèng', + '墰' => ' tán', + '墯' => ' duò', + '壅' => ' yōng', + '壇' => ' tán', + '墭' => ' shèng', + '壔' => ' dǎo', + '壞' => ' huài', + '壝' => ' wěi', + '壜' => ' tán', + '壛' => ' yán', + '壚' => ' lú', + '壙' => ' kuàng', + '壘' => ' lěi', + '壗' => ' jin', + '壖' => ' ruán', + '壕' => ' háo', + '壓' => ' yā', + '壈' => ' lǎn', + '壒' => ' ài', + '壑' => ' hè', + '壐' => ' xǐ', + '壏' => ' xiàn', + '壎' => ' xūn', + '壍' => ' qiàn', + '壌' => ' rǎng', + '壋' => ' dàng', + '壊' => ' huài', + '壉' => ' jù', + '墮' => ' duò', + '墬' => ' dì', + '塹' => ' qiàn', + '墅' => ' shù', + '墏' => ' qiǎng', + '墎' => ' guō', + '墍' => ' xì', + '墌' => ' zhí', + '墋' => ' chěn', + '墊' => ' diàn', + '墉' => ' yōng', + '墈' => ' kàn', + '墇' => ' zhāng', + '墆' => ' zhì', + '墄' => ' cè', + '墑' => ' dì', + '境' => ' jìng', + '墂' => ' biāo', + '墁' => ' màn', + '墀' => ' chí', + '塿' => ' lǒu', + '塾' => ' shú', + '塽' => ' shuǎng', + '塼' => ' zhuān', + '塻' => ' mò', + '塺' => ' méi', + '墐' => ' jìn', + '墒' => ' shāng', + '墫' => ' zūn', + '墠' => ' shàn', + '墪' => ' dūn', + '墩' => ' dūn', + '墨' => ' mò', + '墧' => ' què', + '墦' => ' fán', + '墥' => ' dǒng', + '墤' => ' kuài', + '墣' => ' pú', + '墢' => ' bá', + '墡' => ' shàn', + '墟' => ' xū', + '墓' => ' mù', + '增' => ' zēng', + '墝' => ' qiāo', + '墜' => ' zhuì', + '墛' => ' wei', + '墚' => ' liáng', + '墙' => ' qiáng', + '墘' => ' qián', + '増' => ' zēng', + '墖' => ' tǎ', + '墕' => ' yàn', + '墔' => ' cuī', + '妯' => ' zhóu', + '妱' => ' zhāo', + '子' => ' zi', + '嫃' => ' zhēn', + '嫍' => ' tāo', + '嫌' => ' xián', + '嫋' => ' niǎo', + '嫊' => ' sù', + '嫉' => ' jí', + '嫈' => ' yīng', + '嫇' => ' míng', + '嫆' => ' róng', + '嫅' => ' jiē', + '嫄' => ' yuán', + '嫂' => ' sǎo', + '嫏' => ' láng', + '嫁' => ' jià', + '嫀' => ' qín', + '媿' => ' kuì', + '媾' => ' gòu', + '媽' => ' mā', + '媼' => ' ǎo', + '媻' => ' pán', + '媺' => ' měi', + '媹' => ' liú', + '媸' => ' chī', + '嫎' => ' páng', + '嫐' => ' nǎo', + '媶' => ' róng', + '嫝' => ' kāng', + '嫧' => ' zé', + '嫦' => ' cháng', + '嫥' => ' zhuān', + '嫤' => ' jǐn', + '嫣' => ' yān', + '嫢' => ' guī', + '嫡' => ' dí', + '嫠' => ' lí', + '嫟' => ' nì', + '嫞' => ' yōng', + '嫜' => ' zhāng', + '嫑' => ' báo', + '嫛' => ' yī', + '嫚' => ' mān', + '嫙' => ' xuán', + '嫘' => ' léi', + '嫗' => ' yù', + '嫖' => ' piáo', + '嫕' => ' yì', + '嫔' => ' pín', + '嫓' => ' pì', + '嫒' => ' ài', + '媷' => ' rù', + '媵' => ' yìng', + '嫩' => ' nèn', + '媏' => ' duān', + '媙' => ' wēi', + '媘' => ' jiē', + '媗' => ' xuān', + '媖' => ' yīng', + '媕' => ' ān', + '媔' => ' mián', + '媓' => ' huáng', + '媒' => ' méi', + '媑' => ' zhòng', + '媐' => ' yí', + '媎' => ' jiě', + '媛' => ' yuàn', + '媍' => ' fù', + '媌' => ' miáo', + '媋' => ' chūn', + '媊' => ' qián', + '媉' => ' wò', + '媈' => ' huī', + '媇' => ' qīn', + '媆' => ' ruǎn', + '媅' => ' dān', + '媄' => ' měi', + '媚' => ' mèi', + '媜' => ' zhēng', + '媴' => ' yuán', + '媩' => ' hú', + '媳' => ' xí', + '媲' => ' pì', + '媱' => ' yáo', + '媰' => ' chú', + '媯' => ' guī', + '媮' => ' tōu', + '媭' => ' xū', + '媬' => ' bǎo', + '媫' => ' qie', + '媪' => ' ǎo', + '媨' => ' jiù', + '媝' => ' qiū', + '媧' => ' wā', + '媦' => ' wèi', + '媥' => ' piān', + '媤' => ' sī', + '媣' => ' rǎn', + '媢' => ' mào', + '媡' => ' liàn', + '媠' => ' tuǒ', + '媟' => ' xiè', + '媞' => ' shì', + '嫨' => ' hān', + '嫪' => ' lào', + '媂' => ' dì', + '嬫' => ' róng', + '嬵' => ' mián', + '嬴' => ' yíng', + '嬳' => ' yuè', + '嬲' => ' niǎo', + '嬱' => ' cán', + '嬰' => ' yīng', + '嬯' => ' tái', + '嬮' => ' yān', + '嬭' => ' nǎi', + '嬬' => ' rú', + '嬪' => ' pín', + '嬷' => ' mā', + '嬩' => ' yú', + '嬨' => ' cí', + '嬧' => ' jìn', + '嬦' => ' chóu', + '嬥' => ' tiǎo', + '嬤' => ' mā', + '嬣' => ' níng', + '嬢' => ' niáng', + '嬡' => ' ài', + '嬠' => ' cān', + '嬶' => ' bi', + '嬸' => ' shěn', + '嬞' => ' dǒng', + '孅' => ' qiān', + '孏' => ' lǎn', + '孎' => ' zhú', + '孍' => ' yán', + '孌' => ' luán', + '孋' => ' lí', + '孊' => ' mǐ', + '孉' => ' quán', + '孈' => ' huì', + '孇' => ' shuāng', + '孆' => ' yīng', + '孄' => ' lǎn', + '嬹' => ' xìng', + '孃' => ' niáng', + '孂' => ' jiǎo', + '孁' => ' líng', + '孀' => ' shuāng', + '嬿' => ' yàn', + '嬾' => ' lǎn', + '嬽' => ' yuān', + '嬼' => ' liǔ', + '嬻' => ' dú', + '嬺' => ' nì', + '嬟' => ' yì', + '嬝' => ' niǎo', + '嫫' => ' mó', + '嫷' => ' tuǒ', + '嬁' => ' dēng', + '嬀' => ' guī', + '嫿' => ' huà', + '嫾' => ' lián', + '嫽' => ' liáo', + '嫼' => ' mò', + '嫻' => ' xián', + '嫺' => ' xián', + '嫹' => ' máo', + '嫸' => ' zhǎn', + '嫶' => ' qiáo', + '嬃' => ' xū', + '嫵' => ' wǔ', + '嫴' => ' gū', + '嫳' => ' piè', + '嫲' => ' ma', + '嫱' => ' qiáng', + '嫰' => ' nèn', + '嫯' => ' ào', + '嫮' => ' hù', + '嫭' => ' hù', + '嫬' => ' zhē', + '嬂' => ' zhí', + '嬄' => ' yī', + '嬜' => ' xīn', + '嬑' => ' yì', + '嬛' => ' huán', + '嬚' => ' liǎn', + '嬙' => ' qiáng', + '嬘' => ' suì', + '嬗' => ' shàn', + '嬖' => ' bì', + '嬕' => ' shì', + '嬔' => ' fù', + '嬓' => ' jiào', + '嬒' => ' huì', + '嬐' => ' xiān', + '嬅' => ' huà', + '嬏' => ' fān', + '嬎' => ' fàn', + '嬍' => ' měi', + '嬌' => ' jiāo', + '嬋' => ' chán', + '嬊' => ' yàn', + '嬉' => ' xī', + '嬈' => ' ráo', + '嬇' => ' kuì', + '嬆' => ' xī', + '媃' => ' róu', + '媁' => ' wéi', + '妲' => ' dá', + '姲' => ' yàn', + '姼' => ' shí', + '姻' => ' yīn', + '姺' => ' shēn', + '姹' => ' chà', + '姸' => ' yán', + '姷' => ' yòu', + '姶' => ' è', + '姵' => ' pèi', + '姴' => ' liè', + '姳' => ' mǐng', + '姱' => ' kuā', + '姾' => ' quán', + '姰' => ' jūn', + '姯' => ' guāng', + '姮' => ' héng', + '姭' => ' xiàn', + '姬' => ' jī', + '姫' => ' jī', + '姪' => ' zhí', + '姩' => ' niàn', + '姨' => ' yí', + '姧' => ' jiān', + '姽' => ' guǐ', + '姿' => ' zī', + '姥' => ' lǎo', + '娌' => ' lǐ', + '娖' => ' chuò', + '娕' => ' chuò', + '娔' => ' kè', + '娓' => ' wěi', + '娒' => ' méi', + '娑' => ' suō', + '娐' => ' fū', + '娏' => ' máng', + '娎' => ' xiè', + '娍' => ' chéng', + '娋' => ' shào', + '娀' => ' sōng', + '娊' => ' xiàn', + '娉' => ' pīng', + '娈' => ' luán', + '娇' => ' jiāo', + '娆' => ' ráo', + '娅' => ' yà', + '娄' => ' lóu', + '娃' => ' wá', + '娂' => ' hóng', + '威' => ' wēi', + '姦' => ' jiān', + '姤' => ' gòu', + '娘' => ' niáng', + '妾' => ' qiè', + '姈' => ' líng', + '姇' => ' fū', + '姆' => ' mǔ', + '姅' => ' bàn', + '姄' => ' mín', + '姃' => ' zhēng', + '姂' => ' fá', + '姁' => ' xǔ', + '姀' => ' hé', + '妿' => ' ē', + '妽' => ' shēn', + '姊' => ' zǐ', + '妼' => ' bì', + '妻' => ' qī', + '妺' => ' mò', + '妹' => ' mèi', + '妸' => ' ē', + '妷' => ' zhí', + '妶' => ' xián', + '妵' => ' tǒu', + '妴' => ' yuàn', + '妳' => ' nǎi', + '姉' => ' zǐ', + '始' => ' shǐ', + '姣' => ' jiāo', + '姘' => ' pīn', + '姢' => ' juān', + '姡' => ' huá', + '姠' => ' xiàng', + '姟' => ' gāi', + '姞' => ' jí', + '姝' => ' shū', + '姜' => ' jiāng', + '姛' => ' dòng', + '姚' => ' yáo', + '姙' => ' rèn', + '姗' => ' shān', + '姌' => ' rǎn', + '姖' => ' jù', + '姕' => ' zī', + '委' => ' wěi', + '姓' => ' xìng', + '姒' => ' sì', + '姑' => ' gū', + '姐' => ' jiě', + '姏' => ' mán', + '姎' => ' yāng', + '姍' => ' shān', + '娗' => ' tǐng', + '娙' => ' xíng', + '媀' => ' yù', + '婛' => ' jīng', + '婥' => ' nào', + '婤' => ' chōu', + '婣' => ' yīn', + '婢' => ' bì', + '婡' => ' lái', + '婠' => ' wān', + '婟' => ' hù', + '婞' => ' xìng', + '婝' => ' diàn', + '婜' => ' qiān', + '婚' => ' hūn', + '婧' => ' jìng', + '婙' => ' jìng', + '婘' => ' quán', + '婗' => ' ní', + '婖' => ' tiān', + '婕' => ' jié', + '婔' => ' fei', + '婓' => ' fēi', + '婒' => ' tán', + '婑' => ' ruí', + '婐' => ' wǒ', + '婦' => ' fù', + '婨' => ' lún', + '婎' => ' huī', + '婵' => ' chán', + '婿' => ' xù', + '婾' => ' tōu', + '婽' => ' jiǎ', + '婼' => ' chuò', + '婻' => ' nàn', + '婺' => ' wù', + '婹' => ' yǎo', + '婸' => ' dàng', + '婷' => ' tíng', + '婶' => ' shěn', + '婴' => ' yīng', + '婩' => ' àn', + '婳' => ' huà', + '婲' => ' hua', + '婱' => ' xián', + '婰' => ' diǎn', + '婯' => ' lì', + '婮' => ' jū', + '婭' => ' yà', + '婬' => ' yín', + '婫' => ' kūn', + '婪' => ' lán', + '婏' => ' fàn', + '婍' => ' qǐ', + '娚' => ' nán', + '娦' => ' pín', + '娰' => ' sì', + '娯' => ' yú', + '娮' => ' yán', + '娭' => ' āi', + '娬' => ' wǔ', + '娫' => ' yán', + '娪' => ' wú', + '娩' => ' miǎn', + '娨' => ' xiàn', + '娧' => ' tuì', + '娥' => ' é', + '娲' => ' wā', + '娤' => ' zhuāng', + '娣' => ' dì', + '娢' => ' hán', + '娡' => ' zhì', + '娠' => ' shēn', + '娟' => ' juān', + '娞' => ' něi', + '娝' => ' pōu', + '娜' => ' nà', + '娛' => ' yú', + '娱' => ' yú', + '娳' => ' lì', + '婌' => ' shú', + '婁' => ' lóu', + '婋' => ' xiāo', + '婊' => ' biǎo', + '婉' => ' wǎn', + '婈' => ' líng', + '婇' => ' cāi', + '婆' => ' pó', + '婅' => ' jú', + '婄' => ' pǒu', + '婃' => ' cóng', + '婂' => ' mián', + '婀' => ' ē', + '娴' => ' xián', + '娿' => ' ē', + '娾' => ' ǎi', + '娽' => ' lù', + '娼' => ' chāng', + '娻' => ' dōng', + '娺' => ' zhuó', + '娹' => ' xián', + '娸' => ' qī', + '娷' => ' zhuì', + '娶' => ' qǔ', + '娵' => ' jū', + '皣' => ' yè', +); \ No newline at end of file diff --git a/lib/vendor/overtrue/pinyin/src/DictLoaderInterface.php b/lib/vendor/overtrue/pinyin/src/DictLoaderInterface.php new file mode 100644 index 0000000000..8c5f55bd2b --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/DictLoaderInterface.php @@ -0,0 +1,42 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Pinyin; + +use Closure; + +/** + * Dict loader interface. + */ +interface DictLoaderInterface +{ + /** + * Load dict. + * + *
      +     * [
      +     *     '响应时间' => "[\t]xiǎng[\t]yìng[\t]shí[\t]jiān",
      +     *     '长篇连载' => '[\t]cháng[\t]piān[\t]lián[\t]zǎi',
      +     *     //...
      +     * ]
      +     * 
      + * + * @param Closure $callback + */ + public function map(Closure $callback); + + /** + * Load surname dict. + * + * @param Closure $callback + */ + public function mapSurname(Closure $callback); +} diff --git a/lib/vendor/overtrue/pinyin/src/FileDictLoader.php b/lib/vendor/overtrue/pinyin/src/FileDictLoader.php new file mode 100644 index 0000000000..e9895f9b3b --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/FileDictLoader.php @@ -0,0 +1,76 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Pinyin; + +use Closure; + +/** + * Dict File loader. + */ +class FileDictLoader implements DictLoaderInterface +{ + /** + * Words segment name. + * + * @var string + */ + protected $segmentName = 'words_%s'; + + /** + * Dict path. + * + * @var string + */ + protected $path; + + /** + * Constructor. + * + * @param string $path + */ + public function __construct($path) + { + $this->path = $path; + } + + /** + * Load dict. + * + * @param Closure $callback + */ + public function map(Closure $callback) + { + for ($i = 0; $i < 100; ++$i) { + $segment = $this->path.'/'.sprintf($this->segmentName, $i); + + if (file_exists($segment)) { + $dictionary = (array) include $segment; + $callback($dictionary); + } + } + } + + /** + * Load surname dict. + * + * @param Closure $callback + */ + public function mapSurname(Closure $callback) + { + $surnames = $this->path.'/surnames'; + + if (file_exists($surnames)) { + $dictionary = (array) include $surnames; + $callback($dictionary); + } + } +} diff --git a/lib/vendor/overtrue/pinyin/src/GeneratorFileDictLoader.php b/lib/vendor/overtrue/pinyin/src/GeneratorFileDictLoader.php new file mode 100644 index 0000000000..e7da6421a7 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/GeneratorFileDictLoader.php @@ -0,0 +1,145 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Pinyin; + +use Closure; +use SplFileObject; +use Generator; + +/** + * Generator syntax(yield) Dict File loader. + */ +class GeneratorFileDictLoader implements DictLoaderInterface +{ + /** + * Data directory. + * + * @var string + */ + protected $path; + + /** + * Words segment name. + * + * @var string + */ + protected $segmentName = 'words_%s'; + + /** + * SplFileObjects. + * + * @var array + */ + protected static $handles = []; + + /** + * surnames. + * + * @var SplFileObject + */ + protected static $surnamesHandle; + + /** + * Constructor. + * + * @param string $path + */ + public function __construct($path) + { + $this->path = $path; + + for ($i = 0; $i < 100; ++$i) { + $segment = $this->path.'/'.sprintf($this->segmentName, $i); + + if (file_exists($segment) && is_file($segment)) { + array_push(static::$handles, $this->openFile($segment)); + } + } + } + + /** + * Construct a new file object. + * + * @param string $filename file path + * @param string $mode file open mode + * + * @return SplFileObject + */ + protected function openFile($filename, $mode = 'r') + { + return new SplFileObject($filename, $mode); + } + + /** + * get Generator syntax. + * + * @param array $handles SplFileObjects + * + * @return Generator + */ + protected function getGenerator(array $handles) + { + foreach ($handles as $handle) { + $handle->seek(0); + while (false === $handle->eof()) { + $string = str_replace(['\'', ' ', PHP_EOL, ','], '', $handle->fgets()); + + if (false === strpos($string, '=>')) { + continue; + } + + list($string, $pinyin) = explode('=>', $string); + + yield $string => $pinyin; + } + } + } + + /** + * Traverse the stream. + * + * @param Generator $generator + * @param Closure $callback + * + * @author Seven Du + */ + protected function traversing(Generator $generator, Closure $callback) + { + foreach ($generator as $string => $pinyin) { + $callback([$string => $pinyin]); + } + } + + /** + * Load dict. + * + * @param Closure $callback + */ + public function map(Closure $callback) + { + $this->traversing($this->getGenerator(static::$handles), $callback); + } + + /** + * Load surname dict. + * + * @param Closure $callback + */ + public function mapSurname(Closure $callback) + { + if (!static::$surnamesHandle instanceof SplFileObject) { + static::$surnamesHandle = $this->openFile($this->path.'/surnames'); + } + + $this->traversing($this->getGenerator([static::$surnamesHandle]), $callback); + } +} diff --git a/lib/vendor/overtrue/pinyin/src/MemoryFileDictLoader.php b/lib/vendor/overtrue/pinyin/src/MemoryFileDictLoader.php new file mode 100644 index 0000000000..e540fb8518 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/MemoryFileDictLoader.php @@ -0,0 +1,96 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Pinyin; + +use Closure; + +/** + * Memory Dict File loader. + */ +class MemoryFileDictLoader implements DictLoaderInterface +{ + /** + * Data directory. + * + * @var string + */ + protected $path; + + /** + * Words segment name. + * + * @var string + */ + protected $segmentName = 'words_%s'; + + /** + * Segment files. + * + * @var array + */ + protected $segments = array(); + + /** + * Surname cache. + * + * @var array + */ + protected $surnames = array(); + + /** + * Constructor. + * + * @param string $path + */ + public function __construct($path) + { + $this->path = $path; + + for ($i = 0; $i < 100; ++$i) { + $segment = $path.'/'.sprintf($this->segmentName, $i); + + if (file_exists($segment)) { + $this->segments[] = (array) include $segment; + } + } + } + + /** + * Load dict. + * + * @param Closure $callback + */ + public function map(Closure $callback) + { + foreach ($this->segments as $dictionary) { + $callback($dictionary); + } + } + + /** + * Load surname dict. + * + * @param Closure $callback + */ + public function mapSurname(Closure $callback) + { + if (empty($this->surnames)) { + $surnames = $this->path.'/surnames'; + + if (file_exists($surnames)) { + $this->surnames = (array) include $surnames; + } + } + + $callback($this->surnames); + } +} diff --git a/lib/vendor/overtrue/pinyin/src/Pinyin.php b/lib/vendor/overtrue/pinyin/src/Pinyin.php new file mode 100644 index 0000000000..8f6f2aa1a7 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/Pinyin.php @@ -0,0 +1,356 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Pinyin; + +use InvalidArgumentException; + +/* + * Chinese to pinyin translator. + * + * @author overtrue + * @copyright 2015 overtrue + * + * @link https://github.com/overtrue/pinyin + * @link http://overtrue.me + */ + +/** + * Class Pinyin. + * + * @author overtrue + */ +class Pinyin +{ + /** + * Dict loader. + * + * @var \Overtrue\Pinyin\DictLoaderInterface + */ + protected $loader; + + /** + * Punctuations map. + * + * @var array + */ + protected $punctuations = array( + ',' => ',', + '。' => '.', + '!' => '!', + '?' => '?', + ':' => ':', + '“' => '"', + '”' => '"', + '‘' => "'", + '’' => "'", + '_' => '_', + ); + + /** + * Constructor. + * + * @param string $loaderName + */ + public function __construct($loaderName = null) + { + $this->loader = $loaderName ?: 'Overtrue\\Pinyin\\FileDictLoader'; + } + + /** + * Convert string to pinyin. + * + * @param string $string + * @param int $option + * + * @return array + */ + public function convert($string, $option = PINYIN_DEFAULT) + { + $pinyin = $this->romanize($string, $option); + + return $this->splitWords($pinyin, $option); + } + + /** + * Convert string (person name) to pinyin. + * + * @param string $stringName + * @param int $option + * + * @return array + */ + public function name($stringName, $option = PINYIN_NAME) + { + $option = $option | PINYIN_NAME; + + $pinyin = $this->romanize($stringName, $option); + + return $this->splitWords($pinyin, $option); + } + + /** + * Return a pinyin permalink from string. + * + * @param string $string + * @param string $delimiter + * @param int $option + * + * @return string + */ + public function permalink($string, $delimiter = '-', $option = PINYIN_DEFAULT) + { + if (\is_int($delimiter)) { + list($option, $delimiter) = array($delimiter, '-'); + } + + if (!in_array($delimiter, array('_', '-', '.', ''), true)) { + throw new InvalidArgumentException("Delimiter must be one of: '_', '-', '', '.'."); + } + + return implode($delimiter, $this->convert($string, $option | \PINYIN_KEEP_NUMBER | \PINYIN_KEEP_ENGLISH)); + } + + /** + * Return first letters. + * + * @param string $string + * @param string $delimiter + * @param int $option + * + * @return string + */ + public function abbr($string, $delimiter = '', $option = PINYIN_DEFAULT) + { + if (\is_int($delimiter)) { + list($option, $delimiter) = array($delimiter, ''); + } + + return implode($delimiter, array_map(function ($pinyin) { + return \is_numeric($pinyin) ? $pinyin : mb_substr($pinyin, 0, 1); + }, $this->convert($string, $option))); + } + + /** + * Chinese phrase to pinyin. + * + * @param string $string + * @param string $delimiter + * @param int $option + * + * @return string + */ + public function phrase($string, $delimiter = ' ', $option = PINYIN_DEFAULT) + { + if (\is_int($delimiter)) { + list($option, $delimiter) = array($delimiter, ' '); + } + + return implode($delimiter, $this->convert($string, $option)); + } + + /** + * Chinese to pinyin sentence. + * + * @param string $string + * @param string $delimiter + * @param int $option + * + * @return string + */ + public function sentence($string, $delimiter = ' ', $option = \PINYIN_NO_TONE) + { + if (\is_int($delimiter)) { + list($option, $delimiter) = array($delimiter, ' '); + } + + return implode($delimiter, $this->convert($string, $option | \PINYIN_KEEP_PUNCTUATION | \PINYIN_KEEP_ENGLISH | \PINYIN_KEEP_NUMBER)); + } + + /** + * Loader setter. + * + * @param \Overtrue\Pinyin\DictLoaderInterface $loader + * + * @return $this + */ + public function setLoader(DictLoaderInterface $loader) + { + $this->loader = $loader; + + return $this; + } + + /** + * Return dict loader,. + * + * @return \Overtrue\Pinyin\DictLoaderInterface + */ + public function getLoader() + { + if (!($this->loader instanceof DictLoaderInterface)) { + $dataDir = dirname(__DIR__).'/data/'; + + $loaderName = $this->loader; + $this->loader = new $loaderName($dataDir); + } + + return $this->loader; + } + + /** + * Convert Chinese to pinyin. + * + * @param string $string + * @param int $option + * + * @return string + */ + protected function romanize($string, $option = \PINYIN_DEFAULT) + { + $string = $this->prepare($string, $option); + + $dictLoader = $this->getLoader(); + + if ($this->hasOption($option, \PINYIN_NAME)) { + $string = $this->convertSurname($string, $dictLoader); + } + + $dictLoader->map(function ($dictionary) use (&$string) { + $string = strtr($string, $dictionary); + }); + + return $string; + } + + /** + * Convert Chinese Surname to pinyin. + * + * @param string $string + * @param \Overtrue\Pinyin\DictLoaderInterface $dictLoader + * + * @return string + */ + protected function convertSurname($string, $dictLoader) + { + $dictLoader->mapSurname(function ($dictionary) use (&$string) { + foreach ($dictionary as $surname => $pinyin) { + if (0 === strpos($string, $surname)) { + $string = $pinyin.mb_substr($string, mb_strlen($surname, 'UTF-8'), mb_strlen($string, 'UTF-8') - 1, 'UTF-8'); + + break; + } + } + }); + + return $string; + } + + /** + * Split pinyin string to words. + * + * @param string $pinyin + * @param string $option + * + * @return array + */ + protected function splitWords($pinyin, $option) + { + $split = array_filter(preg_split('/\s+/i', $pinyin)); + + if (!$this->hasOption($option, PINYIN_TONE)) { + foreach ($split as $index => $pinyin) { + $split[$index] = $this->formatTone($pinyin, $option); + } + } + + return array_values($split); + } + + /** + * @param int $option + * @param int $check + * + * @return bool + */ + public function hasOption($option, $check) + { + return ($option & $check) === $check; + } + + /** + * Pre-process. + * + * @param string $string + * @param int $option + * + * @return string + */ + protected function prepare($string, $option = \PINYIN_DEFAULT) + { + $string = preg_replace_callback('~[a-z0-9_-]+~i', function ($matches) { + return "\t".$matches[0]; + }, $string); + + $regex = array('\p{Han}', '\p{Z}', '\p{M}', "\t"); + + if ($this->hasOption($option, \PINYIN_KEEP_NUMBER)) { + \array_push($regex, '\p{N}'); + } + + if ($this->hasOption($option, \PINYIN_KEEP_ENGLISH)) { + \array_push($regex, 'a-zA-Z'); + } + + if ($this->hasOption($option, \PINYIN_KEEP_PUNCTUATION)) { + $punctuations = array_merge($this->punctuations, array("\t" => ' ', ' ' => ' ')); + $string = trim(str_replace(array_keys($punctuations), $punctuations, $string)); + + \array_push($regex, preg_quote(implode(array_merge(array_keys($this->punctuations), $this->punctuations)), '~')); + } + + return preg_replace(\sprintf('~[^%s]~u', implode($regex)), '', $string); + } + + /** + * Format. + * + * @param string $pinyin + * @param int $option + * + * @return string + */ + protected function formatTone($pinyin, $option = \PINYIN_NO_TONE) + { + $replacements = array( + 'üē' => array('ue', 1), 'üé' => array('ue', 2), 'üě' => array('ue', 3), 'üè' => array('ue', 4), + 'ā' => array('a', 1), 'ē' => array('e', 1), 'ī' => array('i', 1), 'ō' => array('o', 1), 'ū' => array('u', 1), 'ǖ' => array('yu', 1), + 'á' => array('a', 2), 'é' => array('e', 2), 'í' => array('i', 2), 'ó' => array('o', 2), 'ú' => array('u', 2), 'ǘ' => array('yu', 2), + 'ǎ' => array('a', 3), 'ě' => array('e', 3), 'ǐ' => array('i', 3), 'ǒ' => array('o', 3), 'ǔ' => array('u', 3), 'ǚ' => array('yu', 3), + 'à' => array('a', 4), 'è' => array('e', 4), 'ì' => array('i', 4), 'ò' => array('o', 4), 'ù' => array('u', 4), 'ǜ' => array('yu', 4), + ); + + foreach ($replacements as $unicode => $replacement) { + if (false !== strpos($pinyin, $unicode)) { + $umlaut = $replacement[0]; + + // https://zh.wikipedia.org/wiki/%C3%9C + if ($this->hasOption($option, \PINYIN_UMLAUT_V) && 'yu' == $umlaut) { + $umlaut = 'v'; + } + + $pinyin = str_replace($unicode, $umlaut, $pinyin).($this->hasOption($option, PINYIN_ASCII_TONE) ? $replacement[1] : ''); + } + } + + return $pinyin; + } +} diff --git a/lib/vendor/overtrue/pinyin/src/const.php b/lib/vendor/overtrue/pinyin/src/const.php new file mode 100644 index 0000000000..240ecbcc25 --- /dev/null +++ b/lib/vendor/overtrue/pinyin/src/const.php @@ -0,0 +1,20 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +define('PINYIN_DEFAULT', 4096); +define('PINYIN_TONE', 2); +define('PINYIN_NO_TONE', 4); +define('PINYIN_ASCII_TONE', 8); +define('PINYIN_NAME', 16); +define('PINYIN_KEEP_NUMBER', 32); +define('PINYIN_KEEP_ENGLISH', 64); +define('PINYIN_UMLAUT_V', 128); +define('PINYIN_KEEP_PUNCTUATION', 256); diff --git a/lib/vendor/paragonie/constant_time_encoding/LICENSE.txt b/lib/vendor/paragonie/constant_time_encoding/LICENSE.txt new file mode 100644 index 0000000000..91acaca673 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/LICENSE.txt @@ -0,0 +1,48 @@ +The MIT License (MIT) + +Copyright (c) 2016 - 2022 Paragon Initiative Enterprises + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------ +This library was based on the work of Steve "Sc00bz" Thomas. +------------------------------------------------------------------------------ + +The MIT License (MIT) + +Copyright (c) 2014 Steve Thomas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/lib/vendor/paragonie/constant_time_encoding/README.md b/lib/vendor/paragonie/constant_time_encoding/README.md new file mode 100644 index 0000000000..d2572e91ce --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/README.md @@ -0,0 +1,84 @@ +# Constant-Time Encoding + +[![Build Status](https://github.com/paragonie/constant_time_encoding/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/constant_time_encoding/actions) +[![Latest Stable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/stable)](https://packagist.org/packages/paragonie/constant_time_encoding) +[![Latest Unstable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/unstable)](https://packagist.org/packages/paragonie/constant_time_encoding) +[![License](https://poser.pugx.org/paragonie/constant_time_encoding/license)](https://packagist.org/packages/paragonie/constant_time_encoding) +[![Downloads](https://img.shields.io/packagist/dt/paragonie/constant_time_encoding.svg)](https://packagist.org/packages/paragonie/constant_time_encoding) + +Based on the [constant-time base64 implementation made by Steve "Sc00bz" Thomas](https://github.com/Sc00bz/ConstTimeEncoding), +this library aims to offer character encoding functions that do not leak +information about what you are encoding/decoding via processor cache +misses. Further reading on [cache-timing attacks](http://blog.ircmaxell.com/2014/11/its-all-about-time.html). + +Our fork offers the following enhancements: + +* `mbstring.func_overload` resistance +* Unit tests +* Composer- and Packagist-ready +* Base16 encoding +* Base32 encoding +* Uses `pack()` and `unpack()` instead of `chr()` and `ord()` + +## PHP Version Requirements + +Version 2 of this library should work on **PHP 7** or newer. For PHP 5 +support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x). + +If you are adding this as a dependency to a project intended to work on both PHP 5 and PHP 7, please set the required version to `^1|^2` instead of just `^1` or `^2`. + +## How to Install + +```sh +composer require paragonie/constant_time_encoding +``` + +## How to Use + +```php +use ParagonIE\ConstantTime\Encoding; + +// possibly (if applicable): +// require 'vendor/autoload.php'; + +$data = random_bytes(32); +echo Encoding::base64Encode($data), "\n"; +echo Encoding::base32EncodeUpper($data), "\n"; +echo Encoding::base32Encode($data), "\n"; +echo Encoding::hexEncode($data), "\n"; +echo Encoding::hexEncodeUpper($data), "\n"; +``` + +Example output: + +``` +1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE= +2VMKKPSHSWVCVZJ6E7SONRY3ZXCNG3GE6ZZFU7TGJSX7KUKFNLAQ==== +2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq==== +d558a53e4795aa2ae53e27e4e6c71bcdc4d36cc4f6725a7e664caff551456ac1 +D558A53E4795AA2AE53E27E4E6C71BDCC4D36CC4F6725A7E664CAFF551456AC1 +``` + +If you only need a particular variant, you can just reference the +required class like so: + +```php +use ParagonIE\ConstantTime\Base64; +use ParagonIE\ConstantTime\Base32; + +$data = random_bytes(32); +echo Base64::encode($data), "\n"; +echo Base32::encode($data), "\n"; +``` + +Example output: + +``` +1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE= +2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq==== +``` + +## Support Contracts + +If your company uses this library in their products or services, you may be +interested in [purchasing a support contract from Paragon Initiative Enterprises](https://paragonie.com/enterprise). diff --git a/lib/vendor/paragonie/constant_time_encoding/composer.json b/lib/vendor/paragonie/constant_time_encoding/composer.json new file mode 100644 index 0000000000..2fe9717adb --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/composer.json @@ -0,0 +1,56 @@ +{ + "name": "paragonie/constant_time_encoding", + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base64", + "encoding", + "rfc4648", + "base32", + "base16", + "hex", + "bin2hex", + "hex2bin", + "base64_encode", + "base64_decode", + "base32_encode", + "base32_decode" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "support": { + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "ParagonIE\\ConstantTime\\Tests\\": "tests/" + } + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base32.php b/lib/vendor/paragonie/constant_time_encoding/src/Base32.php new file mode 100644 index 0000000000..48d00b9911 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base32.php @@ -0,0 +1,541 @@ + 96 && $src < 123) $ret += $src - 97 + 1; // -64 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 96); + + // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23 + $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 5-bit integers + * into 8-bit integers. + * + * Uppercase variant. + * + * @param int $src + * @return int + */ + protected static function decode5BitsUpper(int $src): int + { + $ret = -1; + + // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + + // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23 + $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 5-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode5Bits(int $src): string + { + $diff = 0x61; + + // if ($src > 25) $ret -= 72; + $diff -= ((25 - $src) >> 8) & 73; + + return \pack('C', $src + $diff); + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 5-bit integers. + * + * Uppercase variant. + * + * @param int $src + * @return string + */ + protected static function encode5BitsUpper(int $src): string + { + $diff = 0x41; + + // if ($src > 25) $ret -= 40; + $diff -= ((25 - $src) >> 8) & 41; + + return \pack('C', $src + $diff); + } + + /** + * @param string $encodedString + * @param bool $upper + * @return string + */ + public static function decodeNoPadding( + #[\SensitiveParameter] + string $encodedString, + bool $upper = false + ): string { + $srcLen = Binary::safeStrlen($encodedString); + if ($srcLen === 0) { + return ''; + } + if (($srcLen & 7) === 0) { + for ($j = 0; $j < 7 && $j < $srcLen; ++$j) { + if ($encodedString[$srcLen - $j - 1] === '=') { + throw new InvalidArgumentException( + "decodeNoPadding() doesn't tolerate padding" + ); + } + } + } + return static::doDecode( + $encodedString, + $upper, + true + ); + } + + /** + * Base32 decoding + * + * @param string $src + * @param bool $upper + * @param bool $strictPadding + * @return string + * + * @throws TypeError + */ + protected static function doDecode( + #[\SensitiveParameter] + string $src, + bool $upper = false, + bool $strictPadding = false + ): string { + // We do this to reduce code duplication: + $method = $upper + ? 'decode5BitsUpper' + : 'decode5Bits'; + + // Remove padding + $srcLen = Binary::safeStrlen($src); + if ($srcLen === 0) { + return ''; + } + if ($strictPadding) { + if (($srcLen & 7) === 0) { + for ($j = 0; $j < 7; ++$j) { + if ($src[$srcLen - 1] === '=') { + $srcLen--; + } else { + break; + } + } + } + if (($srcLen & 7) === 1) { + throw new RangeException( + 'Incorrect padding' + ); + } + } else { + $src = \rtrim($src, '='); + $srcLen = Binary::safeStrlen($src); + } + + $err = 0; + $dest = ''; + // Main loop (no padding): + for ($i = 0; $i + 8 <= $srcLen; $i += 8) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8)); + /** @var int $c0 */ + $c0 = static::$method($chunk[1]); + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + /** @var int $c3 */ + $c3 = static::$method($chunk[4]); + /** @var int $c4 */ + $c4 = static::$method($chunk[5]); + /** @var int $c5 */ + $c5 = static::$method($chunk[6]); + /** @var int $c6 */ + $c6 = static::$method($chunk[7]); + /** @var int $c7 */ + $c7 = static::$method($chunk[8]); + + $dest .= \pack( + 'CCCCC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, + (($c3 << 4) | ($c4 >> 1) ) & 0xff, + (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff, + (($c6 << 5) | ($c7 ) ) & 0xff + ); + $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8; + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); + /** @var int $c0 */ + $c0 = static::$method($chunk[1]); + + if ($i + 6 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + /** @var int $c3 */ + $c3 = static::$method($chunk[4]); + /** @var int $c4 */ + $c4 = static::$method($chunk[5]); + /** @var int $c5 */ + $c5 = static::$method($chunk[6]); + /** @var int $c6 */ + $c6 = static::$method($chunk[7]); + + $dest .= \pack( + 'CCCC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, + (($c3 << 4) | ($c4 >> 1) ) & 0xff, + (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff + ); + $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8; + if ($strictPadding) { + $err |= ($c6 << 5) & 0xff; + } + } elseif ($i + 5 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + /** @var int $c3 */ + $c3 = static::$method($chunk[4]); + /** @var int $c4 */ + $c4 = static::$method($chunk[5]); + /** @var int $c5 */ + $c5 = static::$method($chunk[6]); + + $dest .= \pack( + 'CCCC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, + (($c3 << 4) | ($c4 >> 1) ) & 0xff, + (($c4 << 7) | ($c5 << 2) ) & 0xff + ); + $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8; + } elseif ($i + 4 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + /** @var int $c3 */ + $c3 = static::$method($chunk[4]); + /** @var int $c4 */ + $c4 = static::$method($chunk[5]); + + $dest .= \pack( + 'CCC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, + (($c3 << 4) | ($c4 >> 1) ) & 0xff + ); + $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8; + if ($strictPadding) { + $err |= ($c4 << 7) & 0xff; + } + } elseif ($i + 3 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + /** @var int $c3 */ + $c3 = static::$method($chunk[4]); + + $dest .= \pack( + 'CC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff + ); + $err |= ($c0 | $c1 | $c2 | $c3) >> 8; + if ($strictPadding) { + $err |= ($c3 << 4) & 0xff; + } + } elseif ($i + 2 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + /** @var int $c2 */ + $c2 = static::$method($chunk[3]); + + $dest .= \pack( + 'CC', + (($c0 << 3) | ($c1 >> 2) ) & 0xff, + (($c1 << 6) | ($c2 << 1) ) & 0xff + ); + $err |= ($c0 | $c1 | $c2) >> 8; + if ($strictPadding) { + $err |= ($c2 << 6) & 0xff; + } + } elseif ($i + 1 < $srcLen) { + /** @var int $c1 */ + $c1 = static::$method($chunk[2]); + + $dest .= \pack( + 'C', + (($c0 << 3) | ($c1 >> 2) ) & 0xff + ); + $err |= ($c0 | $c1) >> 8; + if ($strictPadding) { + $err |= ($c1 << 6) & 0xff; + } + } else { + $dest .= \pack( + 'C', + (($c0 << 3) ) & 0xff + ); + $err |= ($c0) >> 8; + } + } + $check = ($err === 0); + if (!$check) { + throw new RangeException( + 'Base32::doDecode() only expects characters in the correct base32 alphabet' + ); + } + return $dest; + } + + /** + * Base32 Encoding + * + * @param string $src + * @param bool $upper + * @param bool $pad + * @return string + * @throws TypeError + */ + protected static function doEncode( + #[\SensitiveParameter] + string $src, + bool $upper = false, + $pad = true + ): string { + // We do this to reduce code duplication: + $method = $upper + ? 'encode5BitsUpper' + : 'encode5Bits'; + + $dest = ''; + $srcLen = Binary::safeStrlen($src); + + // Main loop (no padding): + for ($i = 0; $i + 5 <= $srcLen; $i += 5) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5)); + $b0 = $chunk[1]; + $b1 = $chunk[2]; + $b2 = $chunk[3]; + $b3 = $chunk[4]; + $b4 = $chunk[5]; + $dest .= + static::$method( ($b0 >> 3) & 31) . + static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . + static::$method((($b1 >> 1) ) & 31) . + static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . + static::$method((($b2 << 1) | ($b3 >> 7)) & 31) . + static::$method((($b3 >> 2) ) & 31) . + static::$method((($b3 << 3) | ($b4 >> 5)) & 31) . + static::$method( $b4 & 31); + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); + $b0 = $chunk[1]; + if ($i + 3 < $srcLen) { + $b1 = $chunk[2]; + $b2 = $chunk[3]; + $b3 = $chunk[4]; + $dest .= + static::$method( ($b0 >> 3) & 31) . + static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . + static::$method((($b1 >> 1) ) & 31) . + static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . + static::$method((($b2 << 1) | ($b3 >> 7)) & 31) . + static::$method((($b3 >> 2) ) & 31) . + static::$method((($b3 << 3) ) & 31); + if ($pad) { + $dest .= '='; + } + } elseif ($i + 2 < $srcLen) { + $b1 = $chunk[2]; + $b2 = $chunk[3]; + $dest .= + static::$method( ($b0 >> 3) & 31) . + static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . + static::$method((($b1 >> 1) ) & 31) . + static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . + static::$method((($b2 << 1) ) & 31); + if ($pad) { + $dest .= '==='; + } + } elseif ($i + 1 < $srcLen) { + $b1 = $chunk[2]; + $dest .= + static::$method( ($b0 >> 3) & 31) . + static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . + static::$method((($b1 >> 1) ) & 31) . + static::$method((($b1 << 4) ) & 31); + if ($pad) { + $dest .= '===='; + } + } else { + $dest .= + static::$method( ($b0 >> 3) & 31) . + static::$method( ($b0 << 2) & 31); + if ($pad) { + $dest .= '======'; + } + } + } + return $dest; + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base32Hex.php b/lib/vendor/paragonie/constant_time_encoding/src/Base32Hex.php new file mode 100644 index 0000000000..b868dd0483 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base32Hex.php @@ -0,0 +1,111 @@ + 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47); + + // if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86 + $ret += (((0x60 - $src) & ($src - 0x77)) >> 8) & ($src - 86); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 5-bit integers + * into 8-bit integers. + * + * @param int $src + * @return int + */ + protected static function decode5BitsUpper(int $src): int + { + $ret = -1; + + // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47); + + // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54 + $ret += (((0x40 - $src) & ($src - 0x57)) >> 8) & ($src - 54); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 5-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode5Bits(int $src): string + { + $src += 0x30; + + // if ($src > 0x39) $src += 0x61 - 0x3a; // 39 + $src += ((0x39 - $src) >> 8) & 39; + + return \pack('C', $src); + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 5-bit integers. + * + * Uppercase variant. + * + * @param int $src + * @return string + */ + protected static function encode5BitsUpper(int $src): string + { + $src += 0x30; + + // if ($src > 0x39) $src += 0x41 - 0x3a; // 7 + $src += ((0x39 - $src) >> 8) & 7; + + return \pack('C', $src); + } +} \ No newline at end of file diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base64.php b/lib/vendor/paragonie/constant_time_encoding/src/Base64.php new file mode 100644 index 0000000000..2e3ecc8595 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base64.php @@ -0,0 +1,319 @@ + $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3)); + $b0 = $chunk[1]; + $b1 = $chunk[2]; + $b2 = $chunk[3]; + + $dest .= + static::encode6Bits( $b0 >> 2 ) . + static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . + static::encode6Bits( $b2 & 63); + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); + $b0 = $chunk[1]; + if ($i + 1 < $srcLen) { + $b1 = $chunk[2]; + $dest .= + static::encode6Bits($b0 >> 2) . + static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + static::encode6Bits(($b1 << 2) & 63); + if ($pad) { + $dest .= '='; + } + } else { + $dest .= + static::encode6Bits( $b0 >> 2) . + static::encode6Bits(($b0 << 4) & 63); + if ($pad) { + $dest .= '=='; + } + } + } + return $dest; + } + + /** + * decode from base64 into binary + * + * Base64 character set "./[A-Z][a-z][0-9]" + * + * @param string $encodedString + * @param bool $strictPadding + * @return string + * + * @throws RangeException + * @throws TypeError + */ + public static function decode( + #[\SensitiveParameter] + string $encodedString, + bool $strictPadding = false + ): string { + // Remove padding + $srcLen = Binary::safeStrlen($encodedString); + if ($srcLen === 0) { + return ''; + } + + if ($strictPadding) { + if (($srcLen & 3) === 0) { + if ($encodedString[$srcLen - 1] === '=') { + $srcLen--; + if ($encodedString[$srcLen - 1] === '=') { + $srcLen--; + } + } + } + if (($srcLen & 3) === 1) { + throw new RangeException( + 'Incorrect padding' + ); + } + if ($encodedString[$srcLen - 1] === '=') { + throw new RangeException( + 'Incorrect padding' + ); + } + } else { + $encodedString = \rtrim($encodedString, '='); + $srcLen = Binary::safeStrlen($encodedString); + } + + $err = 0; + $dest = ''; + // Main loop (no padding): + for ($i = 0; $i + 4 <= $srcLen; $i += 4) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, 4)); + $c0 = static::decode6Bits($chunk[1]); + $c1 = static::decode6Bits($chunk[2]); + $c2 = static::decode6Bits($chunk[3]); + $c3 = static::decode6Bits($chunk[4]); + + $dest .= \pack( + 'CCC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff), + ((($c2 << 6) | $c3 ) & 0xff) + ); + $err |= ($c0 | $c1 | $c2 | $c3) >> 8; + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, $srcLen - $i)); + $c0 = static::decode6Bits($chunk[1]); + + if ($i + 2 < $srcLen) { + $c1 = static::decode6Bits($chunk[2]); + $c2 = static::decode6Bits($chunk[3]); + $dest .= \pack( + 'CC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff) + ); + $err |= ($c0 | $c1 | $c2) >> 8; + if ($strictPadding) { + $err |= ($c2 << 6) & 0xff; + } + } elseif ($i + 1 < $srcLen) { + $c1 = static::decode6Bits($chunk[2]); + $dest .= \pack( + 'C', + ((($c0 << 2) | ($c1 >> 4)) & 0xff) + ); + $err |= ($c0 | $c1) >> 8; + if ($strictPadding) { + $err |= ($c1 << 4) & 0xff; + } + } elseif ($strictPadding) { + $err |= 1; + } + } + $check = ($err === 0); + if (!$check) { + throw new RangeException( + 'Base64::decode() only expects characters in the correct base64 alphabet' + ); + } + return $dest; + } + + /** + * @param string $encodedString + * @return string + */ + public static function decodeNoPadding( + #[\SensitiveParameter] + string $encodedString + ): string { + $srcLen = Binary::safeStrlen($encodedString); + if ($srcLen === 0) { + return ''; + } + if (($srcLen & 3) === 0) { + // If $strLen is not zero, and it is divisible by 4, then it's at least 4. + if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') { + throw new InvalidArgumentException( + "decodeNoPadding() doesn't tolerate padding" + ); + } + } + return static::decode( + $encodedString, + true + ); + } + + /** + * Uses bitwise operators instead of table-lookups to turn 6-bit integers + * into 8-bit integers. + * + * Base64 character set: + * [A-Z] [a-z] [0-9] + / + * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f + * + * @param int $src + * @return int + */ + protected static function decode6Bits(int $src): int + { + $ret = -1; + + // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + + // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); + + // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); + + // if ($src == 0x2b) $ret += 62 + 1; + $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63; + + // if ($src == 0x2f) ret += 63 + 1; + $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64; + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits(int $src): string + { + $diff = 0x41; + + // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 + $diff += ((25 - $src) >> 8) & 6; + + // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 + $diff -= ((51 - $src) >> 8) & 75; + + // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15 + $diff -= ((61 - $src) >> 8) & 15; + + // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3 + $diff += ((62 - $src) >> 8) & 3; + + return \pack('C', $src + $diff); + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php b/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php new file mode 100644 index 0000000000..5e98a8f793 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php @@ -0,0 +1,88 @@ + 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45 + $ret += (((0x2d - $src) & ($src - 0x30)) >> 8) & ($src - 45); + + // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 62); + + // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 68); + + // if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 7); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits(int $src): string + { + $src += 0x2e; + + // if ($src > 0x2f) $src += 0x41 - 0x30; // 17 + $src += ((0x2f - $src) >> 8) & 17; + + // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6 + $src += ((0x5a - $src) >> 8) & 6; + + // if ($src > 0x7a) $src += 0x30 - 0x7b; // -75 + $src -= ((0x7a - $src) >> 8) & 75; + + return \pack('C', $src); + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php b/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php new file mode 100644 index 0000000000..9780b14bb0 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php @@ -0,0 +1,82 @@ + 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45 + $ret += (((0x2d - $src) & ($src - 0x3a)) >> 8) & ($src - 45); + + // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 52); + + // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 58); + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits(int $src): string + { + $src += 0x2e; + + // if ($src > 0x39) $src += 0x41 - 0x3a; // 7 + $src += ((0x39 - $src) >> 8) & 7; + + // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6 + $src += ((0x5a - $src) >> 8) & 6; + + return \pack('C', $src); + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php b/lib/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php new file mode 100644 index 0000000000..8192c63d58 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php @@ -0,0 +1,95 @@ + 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + + // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); + + // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); + + // if ($src == 0x2c) $ret += 62 + 1; + $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; + + // if ($src == 0x5f) ret += 63 + 1; + $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64; + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits(int $src): string + { + $diff = 0x41; + + // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 + $diff += ((25 - $src) >> 8) & 6; + + // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 + $diff -= ((51 - $src) >> 8) & 75; + + // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13 + $diff -= ((61 - $src) >> 8) & 13; + + // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3 + $diff += ((62 - $src) >> 8) & 49; + + return \pack('C', $src + $diff); + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/Binary.php b/lib/vendor/paragonie/constant_time_encoding/src/Binary.php new file mode 100644 index 0000000000..5368e4bba7 --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/Binary.php @@ -0,0 +1,93 @@ + $chunk */ + $chunk = \unpack('C', $binString[$i]); + $c = $chunk[1] & 0xf; + $b = $chunk[1] >> 4; + + $hex .= \pack( + 'CC', + (87 + $b + ((($b - 10) >> 8) & ~38)), + (87 + $c + ((($c - 10) >> 8) & ~38)) + ); + } + return $hex; + } + + /** + * Convert a binary string into a hexadecimal string without cache-timing + * leaks, returning uppercase letters (as per RFC 4648) + * + * @param string $binString (raw binary) + * @return string + * @throws TypeError + */ + public static function encodeUpper( + #[\SensitiveParameter] + string $binString + ): string { + $hex = ''; + $len = Binary::safeStrlen($binString); + + for ($i = 0; $i < $len; ++$i) { + /** @var array $chunk */ + $chunk = \unpack('C', $binString[$i]); + $c = $chunk[1] & 0xf; + $b = $chunk[1] >> 4; + + $hex .= \pack( + 'CC', + (55 + $b + ((($b - 10) >> 8) & ~6)), + (55 + $c + ((($c - 10) >> 8) & ~6)) + ); + } + return $hex; + } + + /** + * Convert a hexadecimal string into a binary string without cache-timing + * leaks + * + * @param string $encodedString + * @param bool $strictPadding + * @return string (raw binary) + * @throws RangeException + */ + public static function decode( + #[\SensitiveParameter] + string $encodedString, + bool $strictPadding = false + ): string { + $hex_pos = 0; + $bin = ''; + $c_acc = 0; + $hex_len = Binary::safeStrlen($encodedString); + $state = 0; + if (($hex_len & 1) !== 0) { + if ($strictPadding) { + throw new RangeException( + 'Expected an even number of hexadecimal characters' + ); + } else { + $encodedString = '0' . $encodedString; + ++$hex_len; + } + } + + /** @var array $chunk */ + $chunk = \unpack('C*', $encodedString); + while ($hex_pos < $hex_len) { + ++$hex_pos; + $c = $chunk[$hex_pos]; + $c_num = $c ^ 48; + $c_num0 = ($c_num - 10) >> 8; + $c_alpha = ($c & ~32) - 55; + $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; + + if (($c_num0 | $c_alpha0) === 0) { + throw new RangeException( + 'Expected hexadecimal character' + ); + } + $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); + if ($state === 0) { + $c_acc = $c_val * 16; + } else { + $bin .= \pack('C', $c_acc | $c_val); + } + $state ^= 1; + } + return $bin; + } +} diff --git a/lib/vendor/paragonie/constant_time_encoding/src/RFC4648.php b/lib/vendor/paragonie/constant_time_encoding/src/RFC4648.php new file mode 100644 index 0000000000..7cd2e9909d --- /dev/null +++ b/lib/vendor/paragonie/constant_time_encoding/src/RFC4648.php @@ -0,0 +1,206 @@ + "Zm9v" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base64Encode( + #[\SensitiveParameter] + string $str + ): string { + return Base64::encode($str); + } + + /** + * RFC 4648 Base64 decoding + * + * "Zm9v" -> "foo" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base64Decode( + #[\SensitiveParameter] + string $str + ): string { + return Base64::decode($str, true); + } + + /** + * RFC 4648 Base64 (URL Safe) encoding + * + * "foo" -> "Zm9v" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base64UrlSafeEncode( + #[\SensitiveParameter] + string $str + ): string { + return Base64UrlSafe::encode($str); + } + + /** + * RFC 4648 Base64 (URL Safe) decoding + * + * "Zm9v" -> "foo" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base64UrlSafeDecode( + #[\SensitiveParameter] + string $str + ): string { + return Base64UrlSafe::decode($str, true); + } + + /** + * RFC 4648 Base32 encoding + * + * "foo" -> "MZXW6===" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base32Encode( + #[\SensitiveParameter] + string $str + ): string { + return Base32::encodeUpper($str); + } + + /** + * RFC 4648 Base32 encoding + * + * "MZXW6===" -> "foo" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base32Decode( + #[\SensitiveParameter] + string $str + ): string { + return Base32::decodeUpper($str, true); + } + + /** + * RFC 4648 Base32-Hex encoding + * + * "foo" -> "CPNMU===" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base32HexEncode( + #[\SensitiveParameter] + string $str + ): string { + return Base32::encodeUpper($str); + } + + /** + * RFC 4648 Base32-Hex decoding + * + * "CPNMU===" -> "foo" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base32HexDecode( + #[\SensitiveParameter] + string $str + ): string { + return Base32::decodeUpper($str, true); + } + + /** + * RFC 4648 Base16 decoding + * + * "foo" -> "666F6F" + * + * @param string $str + * @return string + * + * @throws TypeError + */ + public static function base16Encode( + #[\SensitiveParameter] + string $str + ): string { + return Hex::encodeUpper($str); + } + + /** + * RFC 4648 Base16 decoding + * + * "666F6F" -> "foo" + * + * @param string $str + * @return string + */ + public static function base16Decode( + #[\SensitiveParameter] + string $str + ): string { + return Hex::decode($str, true); + } +} diff --git a/lib/vendor/paragonie/random_compat/LICENSE b/lib/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 0000000000..45c7017dfb --- /dev/null +++ b/lib/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/lib/vendor/paragonie/random_compat/build-phar.sh b/lib/vendor/paragonie/random_compat/build-phar.sh new file mode 100755 index 0000000000..b4a5ba31cc --- /dev/null +++ b/lib/vendor/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/lib/vendor/paragonie/random_compat/composer.json b/lib/vendor/paragonie/random_compat/composer.json new file mode 100644 index 0000000000..f2b9c4e510 --- /dev/null +++ b/lib/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,34 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "polyfill", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "vimeo/psalm": "^1", + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + } +} diff --git a/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 0000000000..eb50ebfcd6 --- /dev/null +++ b/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 0000000000..6a1d7f3006 --- /dev/null +++ b/lib/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/lib/vendor/paragonie/random_compat/lib/random.php b/lib/vendor/paragonie/random_compat/lib/random.php new file mode 100644 index 0000000000..c7731a56ff --- /dev/null +++ b/lib/vendor/paragonie/random_compat/lib/random.php @@ -0,0 +1,32 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/lib/vendor/paragonie/random_compat/psalm-autoload.php b/lib/vendor/paragonie/random_compat/psalm-autoload.php new file mode 100644 index 0000000000..d71d1b818c --- /dev/null +++ b/lib/vendor/paragonie/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + + + + diff --git a/lib/vendor/pclzip/pclzip/composer.json b/lib/vendor/pclzip/pclzip/composer.json new file mode 100644 index 0000000000..a4df7fb6e3 --- /dev/null +++ b/lib/vendor/pclzip/pclzip/composer.json @@ -0,0 +1,16 @@ +{ + "name": "pclzip/pclzip", + "type": "library", + "description": "A PHP library that offers compression and extraction functions for Zip formatted archives", + "keywords": ["php", "zip"], + "homepage": "http://www.phpconcept.net/pclzip", + "license": ["LGPL-2.1"], + "authors": [ + { + "name": "Vincent Blavet" + } + ], + "autoload": { + "classmap": ["pclzip.lib.php"] + } +} diff --git a/lib/vendor/pclzip/pclzip/gnu-lgpl.txt b/lib/vendor/pclzip/pclzip/gnu-lgpl.txt new file mode 100644 index 0000000000..583509c7ef --- /dev/null +++ b/lib/vendor/pclzip/pclzip/gnu-lgpl.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/lib/vendor/pclzip/pclzip/pclzip.lib.php b/lib/vendor/pclzip/pclzip/pclzip.lib.php new file mode 100644 index 0000000000..33be0d7869 --- /dev/null +++ b/lib/vendor/pclzip/pclzip/pclzip.lib.php @@ -0,0 +1,5414 @@ +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function create($p_filelist) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } + + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } else { + } + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function add($p_filelist) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } + + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist"); + + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + public function listContent() + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) { + unset($p_list); + + return (0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function extract() + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } + + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Trace + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + + return (0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + public function extractByIndex($p_index) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } + + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + } else { + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array( + PCLZIP_OPT_BY_INDEX, + $p_index + ); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array( + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return (0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function delete() + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + + return (0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + public function deleteByIndex($p_index) + { + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + public function properties() + { + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + + return (0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); + + // ----- Return + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); + + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + public function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) { + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + + // ----- Look if the $p_archive is a string (so a filename) + } elseif (is_string($p_archive)) { + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + public function merge($p_archive_to_add) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) { + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + + // ----- Look if the $p_archive_to_add is a string (so a filename) + } elseif (is_string($p_archive_to_add)) { + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorCode()); + } else { + return ($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorName($p_with_code = false) + { + $v_name = array( + PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', + PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', + PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return ($v_value . ' (' . $this->error_code . ')'); + } else { + return ($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorInfo($p_full = false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorString()); + } else { + if ($p_full) { + return ($this->errorName(true) . " : " . $this->error_string); + } else { + return ($this->error_string . " [code " . $this->error_code . "]"); + } + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** + // ***** ***** + // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + public function privCheckFormat($p_level = 0) + { + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'"); + + return (false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'"); + + return (false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false) + { + $v_result = 1; + + // ----- Read the options + $i = 0; + while ($i < $p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '" . $p_options_list[$i] . "' for this method"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH: + case PCLZIP_OPT_REMOVE_PATH: + case PCLZIP_OPT_ADD_PATH: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i + 1]; + if ((!is_integer($v_value)) || ($v_value < 0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value * 1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + } else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG: + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + case PCLZIP_OPT_BY_PREG: + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT: + case PCLZIP_OPT_ADD_COMMENT: + case PCLZIP_OPT_PREPEND_COMMENT: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i + 1])) { + + // ----- Remove spaces + $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i + 1]); + } elseif (is_integer($p_options_list[$i + 1])) { + $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_work_list = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag = false; + $v_sort_value = 0; + for ($j = 0; $j < sizeof($v_work_list); $j++) { + // ----- Explode the item + $v_item_list = explode("-", $v_work_list[$j]); + $v_size_item_list = sizeof($v_item_list); + + // ----- TBC : Here we might check that each item is a + // real integer ... + + // ----- Look for single value + if ($v_size_item_list == 1) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; + } elseif ($v_size_item_list == 2) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for list sort + if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { + $v_sort_flag = true; + + // ----- TBC : An automatic sort should be writen ... + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; + } + + // ----- Sort the items + if ($v_sort_flag) { + // TBC : To Be Completed + } + + // ----- Next option + $i++; + break; + + // ----- Look for options that request no value + case PCLZIP_OPT_REMOVE_ALL_PATH: + case PCLZIP_OPT_EXTRACT_AS_STRING: + case PCLZIP_OPT_NO_COMPRESSION: + case PCLZIP_OPT_EXTRACT_IN_OUTPUT: + case PCLZIP_OPT_REPLACE_NEWER: + case PCLZIP_OPT_STOP_ON_ERROR: + $v_result_list[$p_options_list[$i]] = true; + break; + + // ----- Look for options that request an octal value + case PCLZIP_OPT_SET_CHMOD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT: + case PCLZIP_CB_POST_EXTRACT: + case PCLZIP_CB_PRE_ADD: + case PCLZIP_CB_POST_ADD: + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i + 1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $p_options_list[$i] . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privOptionDefaultThreshold(&$p_options) + { + $v_result = 1; + + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } + + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + + if ($last == 'g') { + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit * 1073741824; + } + if ($last == 'm') { + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit * 1048576; + } + if ($last == 'k') { + $v_memory_limit = $v_memory_limit * 1024; + } + + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO); + + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) + { + $v_result = 1; + + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + break; + + case PCLZIP_ATT_FILE_NEW_SHORT_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + break; + + case PCLZIP_ATT_FILE_NEW_FULL_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME: + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT: + $p_filedescr['content'] = $v_value; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result = 1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i = 0; $i < sizeof($p_filedescr_list); $i++) { + + // ----- Get filedescr + $v_descr = $p_filedescr_list[$i]; + + // ----- Reduce the filename + $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); + $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); + + // ----- Look for real file or folder + if (file_exists($v_descr['filename'])) { + if (@is_file($v_descr['filename'])) { + $v_descr['type'] = 'file'; + } elseif (@is_dir($v_descr['filename'])) { + $v_descr['type'] = 'folder'; + } elseif (@is_link($v_descr['filename'])) { + // skip + continue; + } else { + // skip + continue; + } + + // ----- Look for string added as file + } elseif (isset($v_descr['content'])) { + $v_descr['type'] = 'virtual_file'; + + // ----- Missing file + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Calculate the stored filename + $this->privCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler; + } else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privOpenFd($p_mode) + { + $v_result = 1; + + // ----- Look if already open + if ($this->zip_fd != 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privCloseFd() + { + $v_result = 1; + + if ($this->zip_fd != 0) { + @fclose($this->zip_fd); + } + $this->zip_fd = 0; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- + // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) { + // ----- Format the filename + $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); + + // ----- Skip empty file names + // TBC : Can this be possible ? not checked in DescrParseAtt ? + if ($p_filedescr_list[$j]['filename'] == "") { + continue; + } + + // ----- Check the filename + if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist"); + + return PclZip::errorCode(); + } + + // ----- Look if it is a file or a dir with no all path remove option + // or a dir with all its path removed + // if ( (is_file($p_filedescr_list[$j]['filename'])) + // || ( is_dir($p_filedescr_list[$j]['filename']) + if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + + // ----- Add the file + $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options); + if ($v_result != 1) { + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = 1; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; + // TBC : Removed $p_header['stored_filename'] = $v_stored_filename; + $p_header['stored_filename'] = $p_filedescr['stored_filename']; + $p_header['extra'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for regular file + if ($p_filedescr['type'] == 'file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = filesize($p_filename); + + // ----- Look for regular folder + } elseif ($p_filedescr['type'] == 'folder') { + $p_header['external'] = 0x00000010; + $p_header['mtime'] = filemtime($p_filename); + $p_header['size'] = filesize($p_filename); + + // ----- Look for virtual file + } elseif ($p_filedescr['type'] == 'virtual_file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = strlen($p_filedescr['content']); + } + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } elseif ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = time(); + } else { + $p_header['mtime'] = filemtime($p_filename); + } + + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + + // ----- Use "in memory" zip algo + } else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + // ----- Look for a virtual file (a file from string) + } elseif ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + // ----- Look for a directory + } elseif ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); + } + + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); + + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); + + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes'); + + return PclZip::errorCode(); + } + + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); + + return PclZip::errorCode(); + } + + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); + + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18; + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); + + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCalculateStoredFilename(&$p_filedescr, &$p_options) + { + $v_result = 1; + + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } else { + $p_remove_all_dir = 0; + } + + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + + // ----- Look for path and/or short name change + } else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'] . '/'; + } + $v_stored_filename = $v_dir . $p_filedescr['new_short_name']; + } else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + + // ----- Look for partial path remove + } elseif ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') { + $p_remove_dir .= "/"; + } + + if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) { + + if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./" . $p_remove_dir; + } + if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } else { + $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir)); + } + } + } + + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); + + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") { + $v_stored_filename = $p_add_dir . $v_stored_filename; + } else { + $v_stored_filename = $p_add_dir . "/" . $v_stored_filename; + } + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteFileHeader(&$p_header) + { + $v_result = 1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralFileHeader(&$p_header) + { + $v_result = 1; + + // TBC + //for (reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result = 1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privList(&$p_list) + { + $v_result = 1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + for ($i = 0; $i < $v_central_dir['entries']; $i++) { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privConvertHeader2FileInfo($p_header, &$p_info) + { + $v_result = 1; + + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result = 1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) { + $p_path = "./" . $p_path; + } + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") { + $p_path = substr($p_path, 0, strlen($p_path) - 1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { + + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { + + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { + + // ----- Look if the directory is in the filename path + if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } + + // ----- Look for a filename + } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ + + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { + + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } + + // ----- Look for no rule, which means extract all the archive + } else { + $v_extract = true; + } + + // ----- Check compression method + if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") "); + + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'"); + + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for extraction in standard output + } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for normal extraction + } else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result = 1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; + } + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external'] & 0x00000010) == 0x00000010) { + + $p_entry['status'] = "filtered"; + + return $v_result; + } + + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + + // ----- Look for path to remove + } elseif ($p_remove_path != "") { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path . "/" . $p_entry['filename']; + } + + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']); + if ($v_inclusion == 0) { + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory"); + + return PclZip::errorCode(); + } + + // ----- Look if file is write protected + } elseif (!is_writeable($p_entry['filename'])) { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected"); + + return PclZip::errorCode(); + } + + // ----- Look if the extracted file is older + } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) { + // ----- Change the file status + if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) { + } else { + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + return PclZip::errorCode(); + } + } + } else { + } + + // ----- Check the directory availability and create it if necessary + } else { + if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) { + $v_dir_to_check = $p_entry['filename']; + } elseif (!strstr($p_entry['filename'], "/")) { + $v_dir_to_check = ""; + } else { + $v_dir_to_check = dirname($p_entry['filename']); + } + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + } else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.'); + + return PclZip::errorCode(); + } + + // ----- Look for using temporary file to unzip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + + // ----- Look for extract in memory + } else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === false) { + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + } + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result = 1; + + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); + + return PclZip::errorCode(); + } + + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); + + // ----- Close the temporary file + @fclose($v_dest_file); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); + + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + @fclose($v_dest_file); + @gzclose($v_src_file); + + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result = 1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result = 1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; + } + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } else { + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === false) { + // TBC + } + } + + // ----- Trace + } else { + // TBC : error : can not extract a folder in a string + } + + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadFileHeader(&$p_header) + { + $v_result = 1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } else { + $p_header['mtime'] = time(); + } + + // TBC + //for (reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadCentralFileHeader(&$p_header) + { + $v_result = 1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) { + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + } else { + $p_header['filename'] = ''; + } + + // ----- Get extra + if ($p_header['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + } else { + $p_header['extra'] = ''; + } + + // ----- Get comment + if ($p_header['comment_len'] != 0) { + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + } else { + $p_header['comment'] = ''; + } + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } else { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + public function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result = 1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadEndCentralDir(&$p_central_dir) + { + $v_result = 1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size - 22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) { + $v_maximum_size = $v_size; + } + @fseek($this->zip_fd, $v_size - $v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.'); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } else { + $p_central_dir['comment'] = ''; + } + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // TBC + //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + + return $v_result; + } + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { + + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { + + // ----- Look if the directory is in the filename path + if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + + // ----- Look for a filename + } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ + + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { + + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } + } else { + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) { + unset($v_header_list[$v_nb_extracted]); + } else { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i = 0; $i < sizeof($v_header_list); $i++) { + + // ----- Calculate the position of the header + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + + // ----- Remove every files : reset the file + } elseif ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + public function privDirCheck($p_dir, $p_is_dir = false) + { + $v_result = 1; + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1) == '/')) { + $p_dir = substr($p_dir, 0, strlen($p_dir) - 1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) { + // ----- Look for parent directory + if ($p_parent_dir != "") { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privMerge(&$p_archive_to_add) + { + $v_result = 1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) { + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) { + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Open the archive_to_add file + if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd) - $v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDuplicate($p_archive_filename) + { + $v_result = 1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('wb')) != 1) { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorLog($p_error_code = 0, $p_error_string = '') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDisableMagicQuotes() + { + $v_result = 1; + + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privSwapBackMagicQuotes() + { + $v_result = 1; + + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- +} + +// End of class +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathReduction() +// Description : +// Parameters : +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilPathReduction($p_dir) +{ + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i = sizeof($v_list) - 1; $i >= 0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } elseif ($v_list[$i] == "..") { + $v_skip++; + } elseif ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/" . $v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + + // ----- Last '/' i.e. indicates a directory + } elseif ($i == (sizeof($v_list) - 1)) { + $v_result = $v_list[$i]; + + // ----- Double '/' inside the path + } else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } else { + $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : ""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../' . $v_result; + $v_skip--; + } + } + } + + // ----- Return + return $v_result; +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathInclusion() +// Description : +// This function indicates if the path $p_path is under the $p_dir tree. Or, +// said in an other way, if the file or sub-dir $p_path is inside the dir +// $p_dir. +// The function indicates also if the path is exactly the same as the dir. +// This function supports path with duplicated '/' like '//', but does not +// support '.' or '..' statements. +// Parameters : +// Return Values : +// 0 if $p_path is not inside directory $p_dir +// 1 if $p_path is inside directory $p_dir +// 2 if $p_path is exactly the same as $p_dir +// -------------------------------------------------------------------------------- +function PclZipUtilPathInclusion($p_dir, $p_path) +{ + $v_result = 1; + + // ----- Look for path beginning by ./ + if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1); + } + if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1); + } + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) { + $j++; + } + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) { + $i++; + } + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } elseif ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilCopyBlock() +// Description : +// Parameters : +// $p_mode : read/write compression mode +// 0 : src & dest normal +// 1 : src gzip, dest normal +// 2 : src normal, dest gzip +// 3 : src & dest gzip +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0) +{ + $v_result = 1; + + if ($p_mode == 0) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 1) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 2) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 3) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilRename() +// Description : +// This function tries to do a simple rename() function. If it fails, it +// tries to copy the $p_src file in a new $p_dest file and then unlink the +// first one. +// Parameters : +// $p_src : Old filename +// $p_dest : New filename +// Return Values : +// 1 on success, 0 on failure. +// -------------------------------------------------------------------------------- +function PclZipUtilRename($p_src, $p_dest) +{ + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } elseif (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilOptionText() +// Description : +// Translate option value in text. Mainly for debug purpose. +// Parameters : +// $p_option : the option value. +// Return Values : +// The option text value. +// -------------------------------------------------------------------------------- +function PclZipUtilOptionText($p_option) +{ + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) { + return $v_key; + } + } + + $v_result = 'Unknown'; + + return $v_result; +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilTranslateWinPath() +// Description : +// Translate windows path by replacing '\' by '/' and optionally removing +// drive letter. +// Parameters : +// $p_path : path to translate. +// $p_remove_disk_letter : true | false +// Return Values : +// The path translated. +// -------------------------------------------------------------------------------- +function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true) +{ + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position + 1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + + return $p_path; +} +// -------------------------------------------------------------------------------- diff --git a/lib/vendor/pclzip/pclzip/readme.txt b/lib/vendor/pclzip/pclzip/readme.txt new file mode 100644 index 0000000000..115c22edf1 --- /dev/null +++ b/lib/vendor/pclzip/pclzip/readme.txt @@ -0,0 +1,421 @@ +// -------------------------------------------------------------------------------- +// PclZip 2.8.2 - readme.txt +// -------------------------------------------------------------------------------- +// License GNU/LGPL - August 2009 +// Vincent Blavet - vincent@phpconcept.net +// http://www.phpconcept.net +// -------------------------------------------------------------------------------- +// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $ +// -------------------------------------------------------------------------------- + + + +0 - Sommaire +============ + 1 - Introduction + 2 - What's new + 3 - Corrected bugs + 4 - Known bugs or limitations + 5 - License + 6 - Warning + 7 - Documentation + 8 - Author + 9 - Contribute + +1 - Introduction +================ + + PclZip is a library that allow you to manage a Zip archive. + + Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip + +2 - What's new +============== + + Version 2.8.2 : + - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with + extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string + can also be modified in the post-extract call back. + **Bugs correction : + - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly + - Remove use of eval() and do direct call to callback functions + - Correct support of 64bits systems (Thanks to WordPress team) + + Version 2.8.1 : + - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is + deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will + automatically replace it by PCLZIP_OPT_BY_PREG. + + Version 2.8 : + - Improve extraction of zip archive for large files by using temporary files + This feature is working like the one defined in r2.7. + Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF, + PCLZIP_OPT_TEMP_FILE_THRESHOLD + - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto + sense of temporary file use. + - Bug correction : Reduce filepath in returned file list to remove ennoying + './/' preambule in file path. + + Version 2.7 : + - Improve creation of zip archive for large files : + PclZip will now autosense the configured memory and use temporary files + when large file is suspected. + This feature can also ne triggered by manual options in create() and add() + methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files, + 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic, + 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size + threshold to use temporary files. + Using "temporary files" rather than "memory" might take more time, but + might give the ability to zip very large files : + Tested on my win laptop with a 88Mo file : + Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo) + Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo) + - Replace use of mktime() by time() to limit the E_STRICT error messages. + - Bug correction : When adding files with full windows path (drive letter) + PclZip is now working. Before, if the drive letter is not the default + path, PclZip was not able to add the file. + + Version 2.6 : + - Code optimisation + - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to + add a comment for a specific file. (Don't really know if this is usefull) + - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string + as a file. + - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with + a file. + - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted + with current time + - Add CRC value in the informations returned back for each file after an + action. + - Add missing closedir() statement. + - When adding a folder, and removing the path of this folder, files were + incorrectly added with a '/' at the beginning. Which means files are + related to root in unix systems. Corrected. + - Add conditional if before constant definition. This will allow users + to redefine constants without changing the file, and then improve + upgrade of pclzip code for new versions. + + Version 2.5 : + - Introduce the ability to add file/folder with individual properties (file descriptor). + This gives for example the ability to change the filename of a zipped file. + . Able to add files individually + . Able to change full name + . Able to change short name + . Compatible with global options + - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME + - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE + - Add a security control feature. PclZip can extract any file in any folder + of a system. People may use this to upload a zip file and try to override + a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the + ability to forgive any directory transversal behavior. + - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path + - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION + - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend + by current path (getcwd()) + + Version 2.4 : + - Code improvment : try to speed up the code by removing unusefull call to pack() + - Correct bug in delete() : delete() should be called with no argument. This was not + the case in 2.3. This is corrected in 2.4. + - Correct a bug in path_inclusion function. When the path has several '../../', the + result was bad. + - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will + disable it while working and det it back to its original value. + This resolve a lots of bad formated archive errors. + - Bug correction : PclZip now correctly unzip file in some specific situation, + when compressed content has same size as uncompressed content. + - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH', + directories are not any more created. + - Code improvment : correct unclosed opendir(), better handling of . and .. in + loops. + + + Version 2.3 : + - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not + give the same result in PHP4 and PHP5 .... + + Version 2.2 : + - Try development of PCLZIP_OPT_CRYPT ..... + However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers, + the result (greater than a long) is not supported by PHP. Even the use of bcmath + functions does not help. I did not find yet a solution ...; + - Add missing '/' at end of directory entries + - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or + error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION. + - Corrected : Bad "version need to extract" field in local file header + - Add private method privCheckFileHeaders() in order to check local and central + file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives + the ability to have a local file header without size, compressed size and crc filled. + - Add a generic status 'error' for file status + - Add control of compression type. PclZip only support deflate compression method. + Before v2.2, PclZip does not check the compression method used in an archive while + extracting. With v2.2 PclZip returns a new error status for a file using an unsupported + compression method. New status is "unsupported_compression". New error code is + PCLZIP_ERR_UNSUPPORTED_COMPRESSION. + - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files + when errors like 'a folder with same name exists' or 'a newer file exists' or + 'a write protected file' exists, rather than set a status for the concerning file + and resume the extract of the zip. + - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the + replacement of the file, even if a newer version of the file exists. + Note that today if a file with the same name already exists but is older it will be + replaced by the extracted one. + - Improve PclZipUtilOption() + - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central + directory structure is the last data in the archive. Crypt encryption/decryption of + zip archive put trailing 0 bytes after decryption. PclZip is now supporting this. + + Version 2.1 : + - Add the ability to abort the extraction by using a user callback function. + The user can now return the value '2' in its callback which indicates to stop the + extraction. For a pre call-back extract is stopped before the extration of the current + file. For a post call back, the extraction is stopped after. + - Add the ability to extract a file (or several files) directly in the standard output. + This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract(). + - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT, + PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments + in the zip archive. + - When merging two archives, the comments are not any more lost, but merged, with a + blank space separator. + - Corrected bug : Files are not deleted when all files are asked to be deleted. + - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature. + + + Version 2.0 : + ***** Warning : Some new features may break the backward compatibility for your scripts. + Please carefully read the readme file. + - Add the ability to delete by Index, name and regular expression. This feature is + performed by the method delete(), which uses the optional parameters + PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG. + - Add the ability to extract by regular expression. To extract by regexp you must use the method + extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG + (depending if you want to use ereg() or preg_match() syntax) followed by the + regular expression pattern. + - Add the ability to extract by index, directly with the extract() method. This is a + code improvment of the extractByIndex() method. + - Add the ability to extract by name. To extract by name you must use the method + extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to + extract or an array of filenames to extract. To extract all a folder, use the folder + name rather than the filename with a '/' at the end. + - Add the ability to add files without compression. This is done with a new attribute + which is PCLZIP_OPT_NO_COMPRESSION. + - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly + in a string without using any file (or temporary file). + - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string. + The default separator is now a comma (,) and not any more a blank space. + THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with + your script. + - Improve algorythm performance by removing the use of temporary files when adding or + extracting files in an archive. + - Add (correct) detection of empty filename zipping. This can occurs when the removed + path is the same + as a zipped dir. The dir is not zipped (['status'] = filtered), only its content. + - Add better support for windows paths (thanks for help from manus@manusfreedom.com). + - Corrected bug : When the archive file already exists with size=0, the add() method + fails. Corrected in 2.0. + - Remove the use of OS_WINDOWS constant. Use php_uname() function rather. + - Control the order of index ranges in extract by index feature. + - Change the internal management of folders (better handling of internal flag). + + + Version 1.3 : + - Removing the double include check. This is now done by include_once() and require_once() + PHP directives. + - Changing the error handling mecanism : Remove the use of an external error library. + The former PclError...() functions are replaced by internal equivalent methods. + By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library. + Introducing the use of constants for error codes rather than integer values. This will help + in futur improvment. + Introduction of error handling functions like errorCode(), errorName() and errorInfo(). + - Remove the deprecated use of calling function with arguments passed by reference. + - Add the calling of extract(), extractByIndex(), create() and add() functions + with variable options rather than fixed arguments. + - Add the ability to remove all the file path while extracting or adding, + without any need to specify the path to remove. + This is available for extract(), extractByIndex(), create() and add() functionS by using + the new variable options parameters : + - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct. + - Ability to change the mode of a file after the extraction (chmod()). + This is available for extract() and extractByIndex() functionS by using + the new variable options parameters. + - PCLZIP_OPT_SET_CHMOD : by setting the value of this option. + - Ability to definition call-back options. These call-back will be called during the adding, + or the extracting of file (extract(), extractByIndex(), create() and add() functions) : + - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user + can trigerred the change the filename of the extracted file. The user can triggered the + skip of the extraction. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file. + Nothing can be triggered from that point. + - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user + can trigerred the change the stored filename of the added file. The user can triggered the + skip of the add. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_ADD : will be called after each add of a file. + Nothing can be triggered from that point. + - Two status are added in the file list returned as function result : skipped & filename_too_long + 'skipped' is used when a call-back function ask for skipping the file. + 'filename_too_long' is used while adding a file with a too long filename to archive (the file is + not added) + - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into + a directory. + - Add a check of the presence of the archive file before some actions (like list, ...) + - Add the initialisation of field "index" in header array. This means that by + default index will be -1 when not explicitly set by the methods. + + Version 1.2 : + - Adding a duplicate function. + - Adding a merge function. The merge function is a "quick merge" function, + it just append the content of an archive at the end of the first one. There + is no check for duplicate files or more recent files. + - Improve the search of the central directory end. + + Version 1.1.2 : + + - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license + (see License section). + - Adding the optional support of a static temporary directory. You will need to configure + the constant PCLZIP_TEMPORARY_DIR if you want to use this feature. + - Improving the rename() function. In some cases rename() does not work (different + Filesystems), so it will be replaced by a copy() + unlink() functions. + + Version 1.1.1 : + + - Maintenance release, no new feature. + + Version 1.1 : + + - New method Add() : adding files in the archive + - New method ExtractByIndex() : partial extract of the archive, files are identified by + their index in the archive + - New method DeleteByIndex() : delete some files/folder entries from the archive, + files are identified by their index in the archive. + - Adding a test of the zlib extension presence. If not present abort the script. + + Version 1.0.1 : + + - No new feature + + +3 - Corrected bugs +================== + + Corrected in Version 2.0 : + - Corrected : During an extraction, if a call-back fucntion is used and try to skip + a file, all the extraction process is stopped. + + Corrected in Version 1.3 : + - Corrected : Support of static synopsis for method extract() is broken. + - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF). + - Corrected : When an extract is done with a remove_path parameter, the entry for + the directory with exactly the same path is not skipped/filtered. + - Corrected : extractByIndex() and deleteByIndex() were not managing index in the + right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This + is due to a sort of the index resulting table that puts 11 before 3-5 (sort on + string and not interger). The sort is temporarilly removed, this means that + you must provide a sorted list of index ranges. + + Corrected in Version 1.2 : + + - Nothing. + + Corrected in Version 1.1.2 : + + - Corrected : Winzip is unable to delete or add new files in a PclZip created archives. + + Corrected in Version 1.1.1 : + + - Corrected : When archived file is not compressed (0% compression), the + extract method fails. + + Corrected in Version 1.1 : + + - Corrected : Adding a complete tree of folder may result in a bad archive + creation. + + Corrected in Version 1.0.1 : + + - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + + +4 - Known bugs or limitations +============================= + + Please publish bugs reports in SourceForge : + http://sourceforge.net/tracker/?group_id=40254&atid=427564 + + In Version 2.x : + - PclZip does only support file uncompressed or compressed with deflate (compression method 8) + - PclZip does not support password protected zip archive + - Some concern were seen when changing mtime of a file while archiving. + Seems to be linked to Daylight Saving Time (PclTest_changing_mtime). + + In Version 1.2 : + + - merge() methods does not check for duplicate files or last date of modifications. + + In Version 1.1 : + + - Limitation : Using 'extract' fields in the file header in the zip archive is not supported. + - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to + add a file in a PclZip created archive. (Corrected in v.1.2) + + In Version 1.0.1 : + + - Adding a complete tree of folder may result in a bad archive + creation. (Corrected in V.1.1). + - Path given to methods must be in the unix format (/) and not the Windows format (\). + Workaround : Use only / directory separators. + - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz + added suffix. Files with these names may already exist and may be overwritten. + Workaround : none. + - PclZip does not check if the zlib extension is present. If it is absent, the zip + file is not created and the lib abort without warning. + Workaround : enable the zlib extension on the php install + + In Version 1.0 : + + - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + (Corrected in v.1.0.1) + - Limitation : Multi-disk zip archive are not supported. + + +5 - License +=========== + + Since version 1.1.2, PclZip Library is released under GNU/LGPL license. + This library is free, so you can use it at no cost. + + HOWEVER, if you release a script, an application, a library or any kind of + code using PclZip library (or a part of it), YOU MUST : + - Indicate in the documentation (or a readme file), that your work + uses PclZip Library, and make a reference to the author and the web site + http://www.phpconcept.net + - Gives the ability to the final user to update the PclZip libary. + + I will also appreciate that you send me a mail (vincent@phpconcept.net), just to + be aware that someone is using PclZip. + + For more information about GNU/LGPL license : http://www.gnu.org + +6 - Warning +================= + + This library and the associated files are non commercial, non professional work. + It should not have unexpected results. However if any damage is caused by this software + the author can not be responsible. + The use of this software is at the risk of the user. + +7 - Documentation +================= + PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php + A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/ + +8 - Author +========== + + This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time. + +9 - Contribute +============== + If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net. + If you can help in financing PhpConcept hosting service, please go to + http://www.phpconcept.net/soutien.php diff --git a/lib/vendor/phpmailer/phpmailer/COMMITMENT b/lib/vendor/phpmailer/phpmailer/COMMITMENT new file mode 100644 index 0000000000..a687e0ddb6 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/COMMITMENT @@ -0,0 +1,46 @@ +GPL Cooperation Commitment +Version 1.0 + +Before filing or continuing to prosecute any legal proceeding or claim +(other than a Defensive Action) arising from termination of a Covered +License, we commit to extend to the person or entity ('you') accused +of violating the Covered License the following provisions regarding +cure and reinstatement, taken from GPL version 3. As used here, the +term 'this License' refers to the specific Covered License being +enforced. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly + and finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you + have received notice of violation of this License (for any work) + from that copyright holder, and you cure the violation prior to 30 + days after your receipt of the notice. + +We intend this Commitment to be irrevocable, and binding and +enforceable against us and assignees of or successors to our +copyrights. + +Definitions + +'Covered License' means the GNU General Public License, version 2 +(GPLv2), the GNU Lesser General Public License, version 2.1 +(LGPLv2.1), or the GNU Library General Public License, version 2 +(LGPLv2), all as published by the Free Software Foundation. + +'Defensive Action' means a legal proceeding or claim that We bring +against you in response to a prior proceeding or claim initiated by +you or your affiliate. + +'We' means each contributor to this repository as of the date of +inclusion of this file, including subsidiaries of a corporate +contributor. + +This work is available under a Creative Commons Attribution-ShareAlike +4.0 International license (https://creativecommons.org/licenses/by-sa/4.0/). diff --git a/lib/vendor/phpmailer/phpmailer/LICENSE b/lib/vendor/phpmailer/phpmailer/LICENSE new file mode 100644 index 0000000000..f166cc57b2 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/lib/vendor/phpmailer/phpmailer/README.md b/lib/vendor/phpmailer/phpmailer/README.md new file mode 100644 index 0000000000..862a4e1a42 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/README.md @@ -0,0 +1,232 @@ +[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://supportukrainenow.org/) + +![PHPMailer](https://raw.github.com/PHPMailer/PHPMailer/master/examples/images/phpmailer.png) + +# PHPMailer – A full-featured email creation and transfer class for PHP + +[![Test status](https://github.com/PHPMailer/PHPMailer/workflows/Tests/badge.svg)](https://github.com/PHPMailer/PHPMailer/actions) +[![codecov.io](https://codecov.io/gh/PHPMailer/PHPMailer/branch/master/graph/badge.svg?token=iORZpwmYmM)](https://codecov.io/gh/PHPMailer/PHPMailer) +[![Latest Stable Version](https://poser.pugx.org/phpmailer/phpmailer/v/stable.svg)](https://packagist.org/packages/phpmailer/phpmailer) +[![Total Downloads](https://poser.pugx.org/phpmailer/phpmailer/downloads)](https://packagist.org/packages/phpmailer/phpmailer) +[![License](https://poser.pugx.org/phpmailer/phpmailer/license.svg)](https://packagist.org/packages/phpmailer/phpmailer) +[![API Docs](https://github.com/phpmailer/phpmailer/workflows/Docs/badge.svg)](https://phpmailer.github.io/PHPMailer/) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/PHPMailer/PHPMailer/badge)](https://api.securityscorecards.dev/projects/github.com/PHPMailer/PHPMailer) + +## Features +- Probably the world's most popular code for sending email from PHP! +- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more +- Integrated SMTP support – send without a local mail server +- Send emails with multiple To, CC, BCC, and Reply-to addresses +- Multipart/alternative emails for mail clients that do not read HTML email +- Add attachments, including inline +- Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings +- Full UTF-8 support when using servers that support `SMTPUTF8`. +- Support for iCal events in multiparts and attachments +- SMTP authentication with `LOGIN`, `PLAIN`, `CRAM-MD5`, and `XOAUTH2` mechanisms over SMTPS and SMTP+STARTTLS transports +- Validates email addresses automatically +- Protects against header injection attacks +- Error messages in over 50 languages! +- DKIM and S/MIME signing support +- Compatible with PHP 5.5 and later, including PHP 8.4 +- Namespaced to prevent name clashes +- Much more! + +## Why you might need it +Many PHP developers need to send email from their code. The only PHP function that supports this directly is [`mail()`](https://www.php.net/manual/en/function.mail.php). However, it does not provide any assistance for making use of popular features such as authentication, HTML messages, and attachments. + +Formatting email correctly is surprisingly difficult. There are myriad overlapping (and conflicting) standards, requiring tight adherence to horribly complicated formatting and encoding rules – the vast majority of code that you'll find online that uses the `mail()` function directly is just plain wrong, if not unsafe! + +The PHP `mail()` function usually sends via a local mail server, typically fronted by a `sendmail` binary on Linux, BSD, and macOS platforms, however, Windows usually doesn't include a local mail server; PHPMailer's integrated SMTP client allows email sending on all platforms without needing a local mail server. Be aware though, that the `mail()` function should be avoided when possible; it's both faster and [safer](https://exploitbox.io/paper/Pwning-PHP-Mail-Function-For-Fun-And-RCE.html) to use SMTP to localhost. + +*Please* don't be tempted to do it yourself – if you don't use PHPMailer, there are many other excellent libraries that +you should look at before rolling your own. Try [Symfony Mailer](https://symfony.com/doc/current/mailer.html), [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail), etc. + +## License +This software is distributed under the [LGPL 2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution. + +## Installation & loading +PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file: + +```json +"phpmailer/phpmailer": "^6.10.0" +``` + +or run + +```sh +composer require phpmailer/phpmailer +``` + +Note that the `vendor` folder and the `vendor/autoload.php` script are generated by Composer; they are not part of PHPMailer. + +If you want to use XOAUTH2 authentication, you will also need to add a dependency on the `league/oauth2-client` and appropriate service adapters package in your `composer.json`, or take a look at +by @decomplexity's [SendOauth2 wrapper](https://github.com/decomplexity/SendOauth2), especially if you're using Microsoft services. + +Alternatively, if you're not using Composer, you +can [download PHPMailer as a zip file](https://github.com/PHPMailer/PHPMailer/archive/master.zip), (note that docs and examples are not included in the zip file), then copy the contents of the PHPMailer folder into one of the `include_path` directories specified in your PHP configuration and load each class file manually: + +```php +SMTPDebug = SMTP::DEBUG_SERVER; //Enable verbose debug output + $mail->isSMTP(); //Send using SMTP + $mail->Host = 'smtp.example.com'; //Set the SMTP server to send through + $mail->SMTPAuth = true; //Enable SMTP authentication + $mail->Username = 'user@example.com'; //SMTP username + $mail->Password = 'secret'; //SMTP password + $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption + $mail->Port = 465; //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS` + + //Recipients + $mail->setFrom('from@example.com', 'Mailer'); + $mail->addAddress('joe@example.net', 'Joe User'); //Add a recipient + $mail->addAddress('ellen@example.com'); //Name is optional + $mail->addReplyTo('info@example.com', 'Information'); + $mail->addCC('cc@example.com'); + $mail->addBCC('bcc@example.com'); + + //Attachments + $mail->addAttachment('/var/tmp/file.tar.gz'); //Add attachments + $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); //Optional name + + //Content + $mail->isHTML(true); //Set email format to HTML + $mail->Subject = 'Here is the subject'; + $mail->Body = 'This is the HTML message body in bold!'; + $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; + + $mail->send(); + echo 'Message has been sent'; +} catch (Exception $e) { + echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}"; +} +``` + +You'll find plenty to play with in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder, which covers many common scenarios including sending through Gmail, building contact forms, sending to mailing lists, and more. + +If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See [the mailing list example](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps) for further guidance. + +That's it. You should now be ready to use PHPMailer! + +## Localization +PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder, you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this: + +```php +//To load the French version +$mail->setLanguage('fr', '/optional/path/to/language/directory/'); +``` + +We welcome corrections and new languages – if you're looking for corrections, run the [Language/TranslationCompletenessTest.php](https://github.com/PHPMailer/PHPMailer/blob/master/test/Language/TranslationCompletenessTest.php) script in the tests folder and it will show any missing translations. + +## Documentation +Start reading at the [GitHub wiki](https://github.com/PHPMailer/PHPMailer/wiki). If you're having trouble, head for [the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting) as it's frequently updated. + +Examples of how to use PHPMailer for common scenarios can be found in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder. If you're looking for a good starting point, we recommend you start with [the Gmail example](https://github.com/PHPMailer/PHPMailer/tree/master/examples/gmail.phps). + +To reduce PHPMailer's deployed code footprint, examples are not included if you load PHPMailer via Composer or via [GitHub's zip file download](https://github.com/PHPMailer/PHPMailer/archive/master.zip), so you'll need to either clone the git repository or use the above links to get to the examples directly. + +Complete generated API documentation is [available online](https://phpmailer.github.io/PHPMailer/). + +You can generate complete API-level documentation by running `phpdoc` in the top-level folder, and documentation will appear in the `docs` folder, though you'll need to have [PHPDocumentor](https://www.phpdoc.org) installed. You may find [the unit tests](https://github.com/PHPMailer/PHPMailer/blob/master/test/PHPMailer/PHPMailerTest.php) a good reference for how to do various operations such as encryption. + +If the documentation doesn't cover what you need, search the [many questions on Stack Overflow](https://stackoverflow.com/questions/tagged/phpmailer), and before you ask a question about "SMTP Error: Could not connect to SMTP host.", [read the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting). + +## Tests +[PHPMailer tests](https://github.com/PHPMailer/PHPMailer/tree/master/test/) use PHPUnit 9, with [a polyfill](https://github.com/Yoast/PHPUnit-Polyfills) to let 9-style tests run on older PHPUnit and PHP versions. + +[![Test status](https://github.com/PHPMailer/PHPMailer/workflows/Tests/badge.svg)](https://github.com/PHPMailer/PHPMailer/actions) + +If this isn't passing, is there something you can do to help? + +## Security +Please disclose any vulnerabilities found responsibly – report security issues to the maintainers privately. + +See [SECURITY](https://github.com/PHPMailer/PHPMailer/tree/master/SECURITY.md) and [PHPMailer's security advisories on GitHub](https://github.com/PHPMailer/PHPMailer/security). + +## Contributing +Please submit bug reports, suggestions, and pull requests to the [GitHub issue tracker](https://github.com/PHPMailer/PHPMailer/issues). + +We're particularly interested in fixing edge cases, expanding test coverage, and updating translations. + +If you found a mistake in the docs, or want to add something, go ahead and amend the wiki – anyone can edit it. + +If you have git clones from prior to the move to the PHPMailer GitHub organisation, you'll need to update any remote URLs referencing the old GitHub location with a command like this from within your clone: + +```sh +git remote set-url upstream https://github.com/PHPMailer/PHPMailer.git +``` + +Please *don't* use the SourceForge or Google Code projects any more; they are obsolete and no longer maintained. + +## Sponsorship +Development time and resources for PHPMailer are provided by [Smartmessages.net](https://info.smartmessages.net/), the world's only privacy-first email marketing system. + +Smartmessages.net privacy-first email marketing logo + +Donations are very welcome, whether in beer 🍺, T-shirts 👕, or cold, hard cash 💰. Sponsorship through GitHub is a simple and convenient way to say "thank you" to PHPMailer's maintainers and contributors – just click the "Sponsor" button [on the project page](https://github.com/PHPMailer/PHPMailer). If your company uses PHPMailer, consider taking part in Tidelift's enterprise support programme. + +## PHPMailer For Enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial +support and maintenance for the open-source packages you use to build your applications. Save time, reduce risk, and +improve code health, while paying the maintainers of the exact packages you +use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-phpmailer?utm_source=packagist-phpmailer-phpmailer&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) + +## Changelog +See [changelog](changelog.md). + +## History +- PHPMailer was originally written in 2001 by Brent R. Matzelle as a [SourceForge project](https://sourceforge.net/projects/phpmailer/). +- [Marcus Bointon](https://github.com/Synchro) (`coolbru` on SF) and Andy Prevost (`codeworxtech`) took over the project in 2004. +- Became an Apache incubator project on Google Code in 2010, managed by Jim Jagielski. +- Marcus created [his fork on GitHub](https://github.com/Synchro/PHPMailer) in 2008. +- Jim and Marcus decide to join forces and use GitHub as the canonical and official repo for PHPMailer in 2013. +- PHPMailer moves to [the PHPMailer organisation](https://github.com/PHPMailer) on GitHub in 2013. + +### What's changed since moving from SourceForge? +- Official successor to the SourceForge and Google Code projects. +- Test suite. +- Continuous integration with GitHub Actions. +- Composer support. +- Public development. +- Additional languages and language strings. +- CRAM-MD5 authentication support. +- Preserves full repo history of authors, commits, and branches from the original SourceForge project. diff --git a/lib/vendor/phpmailer/phpmailer/SECURITY.md b/lib/vendor/phpmailer/phpmailer/SECURITY.md new file mode 100644 index 0000000000..4f34026dfa --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/SECURITY.md @@ -0,0 +1,37 @@ +# Security notices relating to PHPMailer + +Please disclose any security issues or vulnerabilities found through [Tidelift's coordinated disclosure system](https://tidelift.com/security) or to the maintainers privately. + +PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the `$patternselect` parameter to `validateAddress()` is set to `'php'` (the default, defined by `PHPMailer::$validator`), and the global namespace contains a function called `php`, it will be called in preference to the built-in validator of the same name. Mitigated in PHPMailer 6.5.0 by denying the use of simple strings as validator function names. Recorded as [CVE-2021-3603](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-3603). Reported by [Vikrant Singh Chauhan](mailto:vi@hackberry.xyz) via [huntr.dev](https://www.huntr.dev/). + +PHPMailer versions 6.4.1 and earlier contain a possible remote code execution vulnerability through the `$lang_path` parameter of the `setLanguage()` method. If the `$lang_path` parameter is passed unfiltered from user input, it can be set to [a UNC path](https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths), and if an attacker is also able to persuade the server to load a file from that UNC path, a script file under their control may be executed. This vulnerability only applies to systems that resolve UNC paths, typically only Microsoft Windows. +PHPMailer 6.5.0 mitigates this by no longer treating translation files as PHP code, but by parsing their text content directly. This approach avoids the possibility of executing unknown code while retaining backward compatibility. This isn't ideal, so the current translation format is deprecated and will be replaced in the next major release. Recorded as [CVE-2021-34551](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-34551). Reported by [Jilin Diting Information Technology Co., Ltd](https://listensec.com) via Tidelift. + +PHPMailer versions between 6.1.8 and 6.4.0 contain a regression of the earlier CVE-2018-19296 object injection vulnerability as a result of [a fix for Windows UNC paths in 6.1.8](https://github.com/PHPMailer/PHPMailer/commit/e2e07a355ee8ff36aba21d0242c5950c56e4c6f9). Recorded as [CVE-2020-36326](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-36326). Reported by Fariskhi Vidyan via Tidelift. 6.4.1 fixes this issue, and also enforces stricter checks for URL schemes in local path contexts. + +PHPMailer versions 6.1.5 and earlier contain an output escaping bug that occurs in `Content-Type` and `Content-Disposition` when filenames passed into `addAttachment` and other methods that accept attachment names contain double quote characters, in contravention of RFC822 3.4.1. No specific vulnerability has been found relating to this, but it could allow file attachments to bypass attachment filters that are based on matching filename extensions. Recorded as [CVE-2020-13625](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-13625). Reported by Elar Lang of Clarified Security. + +PHPMailer versions prior to 6.0.6 and 5.2.27 are vulnerable to an object injection attack by passing `phar://` paths into `addAttachment()` and other functions that may receive unfiltered local paths, possibly leading to RCE. Recorded as [CVE-2018-19296](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-19296). See [this article](https://knasmueller.net/5-answers-about-php-phar-exploitation) for more info on this type of vulnerability. Mitigated by blocking the use of paths containing URL-protocol style prefixes such as `phar://`. Reported by Sehun Oh of cyberone.kr. + +PHPMailer versions prior to 5.2.24 (released July 26th 2017) have an XSS vulnerability in one of the code examples, [CVE-2017-11503](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-11503). The `code_generator.phps` example did not filter user input prior to output. This file is distributed with a `.phps` extension, so it is not normally executable unless it is explicitly renamed, and the file is not included when PHPMailer is loaded through composer, so it is safe by default. There was also an undisclosed potential XSS vulnerability in the default exception handler (unused by default). Patches for both issues kindly provided by Patrick Monnerat of the Fedora Project. + +PHPMailer versions prior to 5.2.22 (released January 9th 2017) have a local file disclosure vulnerability, [CVE-2017-5223](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-5223). If content passed into `msgHTML()` is sourced from unfiltered user input, relative paths can map to absolute local file paths and added as attachments. Also note that `addAttachment` (just like `file_get_contents`, `passthru`, `unlink`, etc) should not be passed user-sourced params either! Reported by Yongxiang Li of Asiasecurity. + +PHPMailer versions prior to 5.2.20 (released December 28th 2016) are vulnerable to [CVE-2016-10045](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-10045) a remote code execution vulnerability, responsibly reported by [Dawid Golunski](https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10045-Vuln-Patch-Bypass.html), and patched by Paul Buonopane (@Zenexer). + +PHPMailer versions prior to 5.2.18 (released December 2016) are vulnerable to [CVE-2016-10033](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-10033) a remote code execution vulnerability, responsibly reported by [Dawid Golunski](https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html). + +PHPMailer versions prior to 5.2.14 (released November 2015) are vulnerable to [CVE-2015-8476](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-8476) an SMTP CRLF injection bug permitting arbitrary message sending. + +PHPMailer versions prior to 5.2.10 (released May 2015) are vulnerable to [CVE-2008-5619](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2008-5619), a remote code execution vulnerability in the bundled html2text library. This file was removed in 5.2.10, so if you are using a version prior to that and make use of the html2text function, it's vitally important that you upgrade and remove this file. + +PHPMailer versions prior to 2.0.7 and 2.2.1 are vulnerable to [CVE-2012-0796](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0796), an email header injection attack. + +Joomla 1.6.0 uses PHPMailer in an unsafe way, allowing it to reveal local file paths, reported in [CVE-2011-3747](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-3747). + +PHPMailer didn't sanitise the `$lang_path` parameter in `SetLanguage`. This wasn't a problem in itself, but some apps (PHPClassifieds, ATutor) also failed to sanitise user-provided parameters passed to it, permitting semi-arbitrary local file inclusion, reported in [CVE-2010-4914](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-4914), [CVE-2007-2021](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2007-2021) and [CVE-2006-5734](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2006-5734). + +PHPMailer 1.7.2 and earlier contained a possible DDoS vulnerability reported in [CVE-2005-1807](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-1807). + +PHPMailer 1.7 and earlier (June 2003) have a possible vulnerability in the `SendmailSend` method where shell commands may not be sanitised. Reported in [CVE-2007-3215](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2007-3215). + diff --git a/lib/vendor/phpmailer/phpmailer/SMTPUTF8.md b/lib/vendor/phpmailer/phpmailer/SMTPUTF8.md new file mode 100644 index 0000000000..ca284ee216 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/SMTPUTF8.md @@ -0,0 +1,48 @@ +# A short history of UTF-8 in email + +## Background + +For most of its existence, SMTP has been a 7-bit channel, only supporting US-ASCII characters. This has been a problem for many languages, especially those that use non-Latin scripts, and has led to the development of various workarounds. + +The first major improvement, introduced in 1994 in [RFC 1652](https://www.rfc-editor.org/rfc/rfc1652) and extended in 2011 in [RFC 6152](https://www.rfc-editor.org/rfc/rfc6152), was the addition of the `8BITMIME` SMTP extension, which allowed raw 8-bit data to be included in message bodies sent over SMTP. +This allowed the message *contents* to contain 8-bit data, including things like UTF-8 text, even though the SMTP protocol itself was still firmly 7-bit. This worked by having the server switch to 8-bit after the headers, and then back to 7-bit after the completion of a `DATA` command. + +From 1996, messages could support [RFC 2047 encoding](https://www.rfc-editor.org/rfc/rfc2047), which permitted inserting characters from any character set into header *values* (but not names), but only by encoding them in somewhat unreadable ways to allow them to survive passage through a 7-bit channel. An example with a subject of "Schrödinger's cat" would be: + +``` +Subject: =?utf-8?Q=Schr=C3=B6dinger=92s_Cat?= +``` + +Here the accented `ö` is encoded as `=C3=B6`, which is the UTF-8 encoding of the 2-byte character, and the whole thing is wrapped in `=?utf-8?Q?` to indicate that it uses the UTF-8 charset and `quoted-printable` encoding. This is a bit of a hack, and not very human-friendly, but it works. + +Similarly, 8-bit message bodies could be encoded using the same `quoted-printable` and `base64` content transfer encoding (CTE) schemes, which preserved the 8-bit content while encoding it in a format that could survive transmission through a 7-bit channel. + +Domain names were originally also stuck in a 7-bit world, actually even more constrained to only a subset of the US-ASCII character set. But of course, many people want to have domains in their own language/script. Internationalized domain name (IDN) permitted this, using yet another complex encoding scheme called punycode, defined for domain names in 2003 in [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492). This finally allowed the domain part (after the `@`) of email addresses to contain UTF-8, though it was actually an illusion preserved by email client applications. For example, an address of +`user@café.example.com` translates to +`user@xn--caf-dma.example.com` in punycode, rendering it mostly unreadable, but 7-bit friendly, and remaining compatible with email clients that don't know about IDN. + +The one remaining part of email that could not handle UTF-8 is the local part of email addresses (the part before the `@`). + +I've only mentioned UTF-8 here, but most of these approaches also allowed other character sets that were popular, such as [the ISO-8859 family](https://en.wikipedia.org/wiki/ISO/IEC_8859). However, UTF-8 solves so many problems that these other character sets are gradually falling out of favour, as UTF-8 can support all languages. + +This patchwork of overlapping approaches has served us well, but we have to admit that it's a mess. + +## SMTPUTF8 + +`SMTPUTF8` is another SMTP extension, defined in [RFC 6531](https://www.rfc-editor.org/rfc/rfc6531) in 2012. This essentially solves the whole problem, allowing the entire SMTP conversation — commands, headers, and message bodies — to be sent in raw, unencoded UTF-8. + +But there's a problem with this approach: adoption. If you send a UTF-8 message to a recipient whose mail server doesn't support this format, the sender has to somehow downgrade the message to make it survive a transition to 7-bit. This is a hard problem to solve, especially since there is no way to make a 7-bit system support UTF-8 in the local parts of addresses. This downgrade problem is what held up the adoption of `SMTPUTF8` in PHPMailer for many years, but in that time the *de facto* approach has become to simply fail in that situation, and tell the recipient it's time they upgraded their mail server 😅. + +The vast majority of large email providers (gmail, Yahoo, Microsoft, etc), mail servers (postfix, exim, IIS, etc), and mail clients (Apple Mail, Outlook, Thunderbird, etc) now all support SMTPUTF8, so the need for backward compatibility is no longer what it was. + +## SMTPUTF8 in PHPMailer + +Several other PHP email libraries have implemented a halfway solution to `SMTPUTF8`, adding only the ability to support UTF-8 in email addresses, not elsewhere in the protocol. I wanted PHPMailer to do it "the right way", and this has taken much longer. PHPMailer now supports UTF-8 everywhere, and does not need to use transfer or header encodings for UTF-8 text when connecting to an `SMTPUTF8`-capable mail server. + +This support is handled automatically: if you add an email address that requires UTF-8, PHPMailer will use UTF-8 for everything. If not, it will fall back to 7-bit and encode the message as necessary. + +The one place you will need to be careful is in the selection of the address validator. By default, PHPMailer uses PHP's built-in `filter_var` validator, which does not allow UTF-8 email addresses. When PHPMailer spots that you have submitted a UTF-8 address, but have not altered the default validator, it will automatically switch to using a UTF-8-compatible validator. As soon as you do this, any SMTP connection you make will *require* that the server you connect to supports `SMTPUTF8`. You can select this validator explicitly by setting `PHPMailer::$validator = 'eai'` (an acronym for Email Address Internationalization). + +### Postfix gotcha + +Postfix has supported `SMTPUTF8` for a long time, but it has a peculiarity that it does not always advertise that it does so. However, rather surprisingly, if you use UTF-8 in the conversation, it will work anyway. diff --git a/lib/vendor/phpmailer/phpmailer/VERSION b/lib/vendor/phpmailer/phpmailer/VERSION new file mode 100644 index 0000000000..cf79bf90ee --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/VERSION @@ -0,0 +1 @@ +6.10.0 diff --git a/lib/vendor/phpmailer/phpmailer/composer.json b/lib/vendor/phpmailer/phpmailer/composer.json new file mode 100644 index 0000000000..7b008b7c57 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/composer.json @@ -0,0 +1,80 @@ +{ + "name": "phpmailer/phpmailer", + "type": "library", + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + }, + "lock": false + }, + "require": { + "php": ">=5.5.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.2", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "PHPMailer\\Test\\": "test/" + } + }, + "license": "LGPL-2.1-only", + "scripts": { + "check": "./vendor/bin/phpcs", + "test": "./vendor/bin/phpunit --no-coverage", + "coverage": "./vendor/bin/phpunit", + "lint": [ + "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . --show-deprecated -e php,phps --exclude vendor --exclude .git --exclude build" + ] + } +} diff --git a/lib/vendor/phpmailer/phpmailer/get_oauth_token.php b/lib/vendor/phpmailer/phpmailer/get_oauth_token.php new file mode 100644 index 0000000000..0e54a00b63 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/get_oauth_token.php @@ -0,0 +1,182 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2020 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * Get an OAuth2 token from an OAuth2 provider. + * * Install this script on your server so that it's accessible + * as [https/http]:////get_oauth_token.php + * e.g.: http://localhost/phpmailer/get_oauth_token.php + * * Ensure dependencies are installed with 'composer install' + * * Set up an app in your Google/Yahoo/Microsoft account + * * Set the script address as the app's redirect URL + * If no refresh token is obtained when running this file, + * revoke access to your app and run the script again. + */ + +namespace PHPMailer\PHPMailer; + +/** + * Aliases for League Provider Classes + * Make sure you have added these to your composer.json and run `composer install` + * Plenty to choose from here: + * @see https://oauth2-client.thephpleague.com/providers/thirdparty/ + */ +//@see https://github.com/thephpleague/oauth2-google +use League\OAuth2\Client\Provider\Google; +//@see https://packagist.org/packages/hayageek/oauth2-yahoo +use Hayageek\OAuth2\Client\Provider\Yahoo; +//@see https://github.com/stevenmaguire/oauth2-microsoft +use Stevenmaguire\OAuth2\Client\Provider\Microsoft; +//@see https://github.com/greew/oauth2-azure-provider +use Greew\OAuth2\Client\Provider\Azure; + +if (!isset($_GET['code']) && !isset($_POST['provider'])) { + ?> + + +
      +

      Select Provider

      + +
      + +
      + +
      + +
      +

      Enter id and secret

      +

      These details are obtained by setting up an app in your provider's developer console. +

      +

      ClientId:

      +

      ClientSecret:

      +

      TenantID (only relevant for Azure):

      + +
      + + + $clientId, + 'clientSecret' => $clientSecret, + 'redirectUri' => $redirectUri, + 'accessType' => 'offline' +]; + +$options = []; +$provider = null; + +switch ($providerName) { + case 'Google': + $provider = new Google($params); + $options = [ + 'scope' => [ + 'https://mail.google.com/' + ] + ]; + break; + case 'Yahoo': + $provider = new Yahoo($params); + break; + case 'Microsoft': + $provider = new Microsoft($params); + $options = [ + 'scope' => [ + 'wl.imap', + 'wl.offline_access' + ] + ]; + break; + case 'Azure': + $params['tenantId'] = $tenantId; + + $provider = new Azure($params); + $options = [ + 'scope' => [ + 'https://outlook.office.com/SMTP.Send', + 'offline_access' + ] + ]; + break; +} + +if (null === $provider) { + exit('Provider missing'); +} + +if (!isset($_GET['code'])) { + //If we don't have an authorization code then get one + $authUrl = $provider->getAuthorizationUrl($options); + $_SESSION['oauth2state'] = $provider->getState(); + header('Location: ' . $authUrl); + exit; + //Check given state against previously stored one to mitigate CSRF attack +} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { + unset($_SESSION['oauth2state']); + unset($_SESSION['provider']); + exit('Invalid state'); +} else { + unset($_SESSION['provider']); + //Try to get an access token (using the authorization code grant) + $token = $provider->getAccessToken( + 'authorization_code', + [ + 'code' => $_GET['code'] + ] + ); + //Use this to interact with an API on the users behalf + //Use this to get a new access token if the old one expires + echo 'Refresh Token: ', htmlspecialchars($token->getRefreshToken()); +} diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-af.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-af.php new file mode 100644 index 0000000000..0b2a72d524 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-af.php @@ -0,0 +1,26 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'خطأ SMTP : لا يمكن تأكيد الهوية.'; +$PHPMAILER_LANG['connect_host'] = 'خطأ SMTP: لا يمكن الاتصال بالخادم SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'خطأ SMTP: لم يتم قبول المعلومات .'; +$PHPMAILER_LANG['empty_message'] = 'نص الرسالة فارغ'; +$PHPMAILER_LANG['encoding'] = 'ترميز غير معروف: '; +$PHPMAILER_LANG['execute'] = 'لا يمكن تنفيذ : '; +$PHPMAILER_LANG['file_access'] = 'لا يمكن الوصول للملف: '; +$PHPMAILER_LANG['file_open'] = 'خطأ في الملف: لا يمكن فتحه: '; +$PHPMAILER_LANG['from_failed'] = 'خطأ على مستوى عنوان المرسل : '; +$PHPMAILER_LANG['instantiate'] = 'لا يمكن توفير خدمة البريد.'; +$PHPMAILER_LANG['invalid_address'] = 'الإرسال غير ممكن لأن عنوان البريد الإلكتروني غير صالح: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' برنامج الإرسال غير مدعوم.'; +$PHPMAILER_LANG['provide_address'] = 'يجب توفير عنوان البريد الإلكتروني لمستلم واحد على الأقل.'; +$PHPMAILER_LANG['recipients_failed'] = 'خطأ SMTP: الأخطاء التالية فشل في الارسال لكل من : '; +$PHPMAILER_LANG['signing'] = 'خطأ في التوقيع: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() غير ممكن.'; +$PHPMAILER_LANG['smtp_error'] = 'خطأ على مستوى الخادم SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'لا يمكن تعيين أو إعادة تعيين متغير: '; +$PHPMAILER_LANG['extension_missing'] = 'الإضافة غير موجودة: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php new file mode 100644 index 0000000000..327dfbafaf --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php @@ -0,0 +1,35 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP ত্ৰুটি: প্ৰমাণীকৰণ কৰিব নোৱাৰি'; +$PHPMAILER_LANG['buggy_php'] = 'আপোনাৰ PHP সংস্কৰণ এটা বাগৰ দ্বাৰা প্ৰভাৱিত হয় যাৰ ফলত নষ্ট বাৰ্তা হব পাৰে । ইয়াক সমাধান কৰিবলে, প্ৰেৰণ কৰিবলে SMTP ব্যৱহাৰ কৰক, আপোনাৰ php.ini ত mail.add_x_header বিকল্প নিষ্ক্ৰিয় কৰক, MacOS বা Linux লৈ সলনি কৰক, বা আপোনাৰ PHP সংস্কৰণ 7.0.17+ বা 7.1.3+ লৈ সলনি কৰক ।'; +$PHPMAILER_LANG['connect_host'] = 'SMTP ত্ৰুটি: SMTP চাৰ্ভাৰৰ সৈতে সংযোগ কৰিবলে অক্ষম'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP ত্ৰুটি: তথ্য গ্ৰহণ কৰা হোৱা নাই'; +$PHPMAILER_LANG['empty_message'] = 'বাৰ্তাৰ মূখ্য অংশ খালী।'; +$PHPMAILER_LANG['encoding'] = 'অজ্ঞাত এনকোডিং: '; +$PHPMAILER_LANG['execute'] = 'এক্সিকিউট কৰিব নোৱাৰি: '; +$PHPMAILER_LANG['extension_missing'] = 'সম্প্ৰসাৰণ নোহোৱা হৈছে: '; +$PHPMAILER_LANG['file_access'] = 'ফাইল অভিগম কৰিবলে অক্ষম: '; +$PHPMAILER_LANG['file_open'] = 'ফাইল ত্ৰুটি: ফাইল খোলিবলৈ অক্ষম: '; +$PHPMAILER_LANG['from_failed'] = 'নিম্নলিখিত প্ৰেৰকৰ ঠিকনা(সমূহ) ব্যৰ্থ: '; +$PHPMAILER_LANG['instantiate'] = 'মেইল ফাংচনৰ এটা উদাহৰণ সৃষ্টি কৰিবলে অক্ষম'; +$PHPMAILER_LANG['invalid_address'] = 'প্ৰেৰণ কৰিব নোৱাৰি: অবৈধ ইমেইল ঠিকনা: '; +$PHPMAILER_LANG['invalid_header'] = 'অবৈধ হেডাৰৰ নাম বা মান'; +$PHPMAILER_LANG['invalid_hostentry'] = 'অবৈধ হোষ্টেন্ট্ৰি: '; +$PHPMAILER_LANG['invalid_host'] = 'অবৈধ হস্ট:'; +$PHPMAILER_LANG['mailer_not_supported'] = 'মেইলাৰ সমৰ্থিত নহয়।'; +$PHPMAILER_LANG['provide_address'] = 'আপুনি অন্ততঃ এটা গন্তব্য ইমেইল ঠিকনা দিব লাগিব'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP ত্ৰুটি: নিম্নলিখিত গন্তব্যস্থানসমূহ ব্যৰ্থ: '; +$PHPMAILER_LANG['signing'] = 'স্বাক্ষৰ কৰাত ব্যৰ্থ: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP কড: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'অতিৰিক্ত SMTP তথ্য: '; +$PHPMAILER_LANG['smtp_detail'] = 'বিৱৰণ:'; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP সংযোগ() ব্যৰ্থ'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP চাৰ্ভাৰৰ ত্ৰুটি: '; +$PHPMAILER_LANG['variable_set'] = 'চলক নিৰ্ধাৰণ কৰিব পৰা নগল: '; +$PHPMAILER_LANG['extension_missing'] = 'অনুপস্থিত সম্প্ৰসাৰণ: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php new file mode 100644 index 0000000000..552167ef62 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Greška: Neuspjela prijava.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Greška: Nije moguće spojiti se sa SMTP serverom.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Greška: Podatci nisu prihvaćeni.'; +$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznata kriptografija: '; +$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: '; +$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: '; +$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP Greška: Slanje sa navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Greška: Slanje na navedene e-mail adrese nije uspjelo: '; +$PHPMAILER_LANG['instantiate'] = 'Ne mogu pokrenuti mail funkcionalnost.'; +$PHPMAILER_LANG['invalid_address'] = 'E-mail nije poslan. Neispravna e-mail adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nije podržan.'; +$PHPMAILER_LANG['provide_address'] = 'Definišite barem jednu adresu primaoca.'; +$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Spajanje na SMTP server nije uspjelo.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP greška: '; +$PHPMAILER_LANG['variable_set'] = 'Nije moguće postaviti varijablu ili je vratiti nazad: '; +$PHPMAILER_LANG['extension_missing'] = 'Nedostaje ekstenzija: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php new file mode 100644 index 0000000000..9e92ddaaf7 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Памылка SMTP: памылка ідэнтыфікацыі.'; +$PHPMAILER_LANG['connect_host'] = 'Памылка SMTP: нельга ўстанавіць сувязь з SMTP-серверам.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Памылка SMTP: звесткі непрынятыя.'; +$PHPMAILER_LANG['empty_message'] = 'Пустое паведамленне.'; +$PHPMAILER_LANG['encoding'] = 'Невядомая кадыроўка тэксту: '; +$PHPMAILER_LANG['execute'] = 'Нельга выканаць каманду: '; +$PHPMAILER_LANG['file_access'] = 'Няма доступу да файла: '; +$PHPMAILER_LANG['file_open'] = 'Нельга адкрыць файл: '; +$PHPMAILER_LANG['from_failed'] = 'Няправільны адрас адпраўніка: '; +$PHPMAILER_LANG['instantiate'] = 'Нельга прымяніць функцыю mail().'; +$PHPMAILER_LANG['invalid_address'] = 'Нельга даслаць паведамленне, няправільны email атрымальніка: '; +$PHPMAILER_LANG['provide_address'] = 'Запоўніце, калі ласка, правільны email атрымальніка.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - паштовы сервер не падтрымліваецца.'; +$PHPMAILER_LANG['recipients_failed'] = 'Памылка SMTP: няправільныя атрымальнікі: '; +$PHPMAILER_LANG['signing'] = 'Памылка подпісу паведамлення: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Памылка сувязі з SMTP-серверам.'; +$PHPMAILER_LANG['smtp_error'] = 'Памылка SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Нельга ўстанавіць або перамяніць значэнне пераменнай: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php new file mode 100644 index 0000000000..c41f675dfd --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP грешка: Не може да се удостовери пред сървъра.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP грешка: Не може да се свърже с SMTP хоста.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP грешка: данните не са приети.'; +$PHPMAILER_LANG['empty_message'] = 'Съдържанието на съобщението е празно'; +$PHPMAILER_LANG['encoding'] = 'Неизвестно кодиране: '; +$PHPMAILER_LANG['execute'] = 'Не може да се изпълни: '; +$PHPMAILER_LANG['file_access'] = 'Няма достъп до файл: '; +$PHPMAILER_LANG['file_open'] = 'Файлова грешка: Не може да се отвори файл: '; +$PHPMAILER_LANG['from_failed'] = 'Следните адреси за подател са невалидни: '; +$PHPMAILER_LANG['instantiate'] = 'Не може да се инстанцира функцията mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Невалиден адрес: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' - пощенски сървър не се поддържа.'; +$PHPMAILER_LANG['provide_address'] = 'Трябва да предоставите поне един email адрес за получател.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP грешка: Следните адреси за Получател са невалидни: '; +$PHPMAILER_LANG['signing'] = 'Грешка при подписване: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP провален connect().'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP сървърна грешка: '; +$PHPMAILER_LANG['variable_set'] = 'Не може да се установи или възстанови променлива: '; +$PHPMAILER_LANG['extension_missing'] = 'Липсва разширение: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php new file mode 100644 index 0000000000..4736510804 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php @@ -0,0 +1,35 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP ত্রুটি: প্রমাণীকরণ করতে অক্ষম৷'; +$PHPMAILER_LANG['buggy_php'] = 'আপনার PHP সংস্করণ একটি বাগ দ্বারা প্রভাবিত হয় যার ফলে দূষিত বার্তা হতে পারে। এটি ঠিক করতে, পাঠাতে SMTP ব্যবহার করুন, আপনার php.ini এ mail.add_x_header বিকল্পটি নিষ্ক্রিয় করুন, MacOS বা Linux-এ স্যুইচ করুন, অথবা আপনার PHP সংস্করণকে 7.0.17+ বা 7.1.3+ এ পরিবর্তন করুন।'; +$PHPMAILER_LANG['connect_host'] = 'SMTP ত্রুটি: SMTP সার্ভারের সাথে সংযোগ করতে অক্ষম৷'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP ত্রুটি: ডেটা গ্রহণ করা হয়নি৷'; +$PHPMAILER_LANG['empty_message'] = 'বার্তার অংশটি খালি।'; +$PHPMAILER_LANG['encoding'] = 'অজানা এনকোডিং: '; +$PHPMAILER_LANG['execute'] = 'নির্বাহ করতে অক্ষম: '; +$PHPMAILER_LANG['extension_missing'] = 'এক্সটেনশন অনুপস্থিত:'; +$PHPMAILER_LANG['file_access'] = 'ফাইল অ্যাক্সেস করতে অক্ষম: '; +$PHPMAILER_LANG['file_open'] = 'ফাইল ত্রুটি: ফাইল খুলতে অক্ষম: '; +$PHPMAILER_LANG['from_failed'] = 'নিম্নলিখিত প্রেরকের ঠিকানা(গুলি) ব্যর্থ হয়েছে: '; +$PHPMAILER_LANG['instantiate'] = 'মেল ফাংশনের একটি উদাহরণ তৈরি করতে অক্ষম৷'; +$PHPMAILER_LANG['invalid_address'] = 'পাঠাতে অক্ষম: অবৈধ ইমেল ঠিকানা: '; +$PHPMAILER_LANG['invalid_header'] = 'অবৈধ হেডার নাম বা মান'; +$PHPMAILER_LANG['invalid_hostentry'] = 'অবৈধ হোস্টেন্ট্রি: '; +$PHPMAILER_LANG['invalid_host'] = 'অবৈধ হোস্ট:'; +$PHPMAILER_LANG['mailer_not_supported'] = 'মেইলার সমর্থিত নয়।'; +$PHPMAILER_LANG['provide_address'] = 'আপনাকে অবশ্যই অন্তত একটি গন্তব্য ইমেল ঠিকানা প্রদান করতে হবে৷'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP ত্রুটি: নিম্নলিখিত গন্তব্যগুলি ব্যর্থ হয়েছে: '; +$PHPMAILER_LANG['signing'] = 'স্বাক্ষর করতে ব্যর্থ হয়েছে: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP কোড: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'অতিরিক্ত SMTP তথ্য:'; +$PHPMAILER_LANG['smtp_detail'] = 'বর্ণনা: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP সংযোগ() ব্যর্থ হয়েছে৷'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP সার্ভার ত্রুটি: '; +$PHPMAILER_LANG['variable_set'] = 'পরিবর্তনশীল সেট করা যায়নি: '; +$PHPMAILER_LANG['extension_missing'] = 'অনুপস্থিত এক্সটেনশন: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php new file mode 100644 index 0000000000..34684855a5 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Error SMTP: No s’ha pogut autenticar.'; +$PHPMAILER_LANG['connect_host'] = 'Error SMTP: No es pot connectar al servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Dades no acceptades.'; +$PHPMAILER_LANG['empty_message'] = 'El cos del missatge està buit.'; +$PHPMAILER_LANG['encoding'] = 'Codificació desconeguda: '; +$PHPMAILER_LANG['execute'] = 'No es pot executar: '; +$PHPMAILER_LANG['file_access'] = 'No es pot accedir a l’arxiu: '; +$PHPMAILER_LANG['file_open'] = 'Error d’Arxiu: No es pot obrir l’arxiu: '; +$PHPMAILER_LANG['from_failed'] = 'La(s) següent(s) adreces de remitent han fallat: '; +$PHPMAILER_LANG['instantiate'] = 'No s’ha pogut crear una instància de la funció Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Adreça d’email invalida: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no està suportat'; +$PHPMAILER_LANG['provide_address'] = 'S’ha de proveir almenys una adreça d’email com a destinatari.'; +$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Els següents destinataris han fallat: '; +$PHPMAILER_LANG['signing'] = 'Error al signar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ha fallat el SMTP Connect().'; +$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'No s’ha pogut establir o restablir la variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php new file mode 100644 index 0000000000..e770a1a265 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php @@ -0,0 +1,28 @@ + + * Rewrite and extension of the work by Mikael Stokkebro + * + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Login mislykkedes.'; +$PHPMAILER_LANG['buggy_php'] = 'Din version af PHP er berørt af en fejl, som gør at dine beskeder muligvis vises forkert. For at rette dette kan du skifte til SMTP, slå mail.add_x_header headeren i din php.ini fil fra, skifte til MacOS eller Linux eller opgradere din version af PHP til 7.0.17+ eller 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Forbindelse til SMTP serveren kunne ikke oprettes.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data blev ikke accepteret.'; +$PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold'; +$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: '; +$PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: '; +$PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: '; +$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; +$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; +$PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.'; +$PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: '; +$PHPMAILER_LANG['invalid_header'] = 'Ugyldig header navn eller værdi'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Ugyldig hostentry: '; +$PHPMAILER_LANG['invalid_host'] = 'Ugyldig vært: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; +$PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere fejlede: '; +$PHPMAILER_LANG['signing'] = 'Signeringsfejl: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP kode: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Yderligere SMTP info: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.'; +$PHPMAILER_LANG['smtp_detail'] = 'Detalje: '; +$PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: '; +$PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php new file mode 100644 index 0000000000..e7e59d2b67 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php @@ -0,0 +1,28 @@ + + * @author Crystopher Glodzienski Cardoso + * @author Daniel Cruz + */ + +$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.'; +$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP está afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.'; +$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.'; +$PHPMAILER_LANG['encoding'] = 'Codificación desconocida: '; +$PHPMAILER_LANG['execute'] = 'Imposible ejecutar: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: '; +$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: '; +$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: '; +$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: '; +$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: '; +$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Hostentry inválido: '; +$PHPMAILER_LANG['invalid_host'] = 'Host inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.'; +$PHPMAILER_LANG['provide_address'] = 'Debe proporcionar al menos una dirección de email de destino.'; +$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinos fallaron: '; +$PHPMAILER_LANG['signing'] = 'Error al firmar: '; +$PHPMAILER_LANG['smtp_code'] = 'Código del servidor SMTP: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Información adicional del servidor SMTP: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.'; +$PHPMAILER_LANG['smtp_detail'] = 'Detalle: '; +$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php new file mode 100644 index 0000000000..93addc9e33 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php @@ -0,0 +1,28 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Viga: Autoriseerimise viga.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Viga: Ei õnnestunud luua ühendust SMTP serveriga.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Viga: Vigased andmed.'; +$PHPMAILER_LANG['empty_message'] = 'Tühi kirja sisu'; +$PHPMAILER_LANG["encoding"] = 'Tundmatu kodeering: '; +$PHPMAILER_LANG['execute'] = 'Tegevus ebaõnnestus: '; +$PHPMAILER_LANG['file_access'] = 'Pole piisavalt õiguseid järgneva faili avamiseks: '; +$PHPMAILER_LANG['file_open'] = 'Faili Viga: Faili avamine ebaõnnestus: '; +$PHPMAILER_LANG['from_failed'] = 'Järgnev saatja e-posti aadress on vigane: '; +$PHPMAILER_LANG['instantiate'] = 'mail funktiooni käivitamine ebaõnnestus.'; +$PHPMAILER_LANG['invalid_address'] = 'Saatmine peatatud, e-posti address vigane: '; +$PHPMAILER_LANG['provide_address'] = 'Te peate määrama vähemalt ühe saaja e-posti aadressi.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' maileri tugi puudub.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Viga: Järgnevate saajate e-posti aadressid on vigased: '; +$PHPMAILER_LANG["signing"] = 'Viga allkirjastamisel: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() ebaõnnestus.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP serveri viga: '; +$PHPMAILER_LANG['variable_set'] = 'Ei õnnestunud määrata või lähtestada muutujat: '; +$PHPMAILER_LANG['extension_missing'] = 'Nõutud laiendus on puudu: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php new file mode 100644 index 0000000000..295a47f95c --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php @@ -0,0 +1,28 @@ + + * @author Mohammad Hossein Mojtahedi + */ + +$PHPMAILER_LANG['authenticate'] = 'خطای SMTP: احراز هویت با شکست مواجه شد.'; +$PHPMAILER_LANG['connect_host'] = 'خطای SMTP: اتصال به سرور SMTP برقرار نشد.'; +$PHPMAILER_LANG['data_not_accepted'] = 'خطای SMTP: داده‌ها نا‌درست هستند.'; +$PHPMAILER_LANG['empty_message'] = 'بخش متن پیام خالی است.'; +$PHPMAILER_LANG['encoding'] = 'کد‌گذاری نا‌شناخته: '; +$PHPMAILER_LANG['execute'] = 'امکان اجرا وجود ندارد: '; +$PHPMAILER_LANG['file_access'] = 'امکان دسترسی به فایل وجود ندارد: '; +$PHPMAILER_LANG['file_open'] = 'خطای File: امکان بازکردن فایل وجود ندارد: '; +$PHPMAILER_LANG['from_failed'] = 'آدرس فرستنده اشتباه است: '; +$PHPMAILER_LANG['instantiate'] = 'امکان معرفی تابع ایمیل وجود ندارد.'; +$PHPMAILER_LANG['invalid_address'] = 'آدرس ایمیل معتبر نیست: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer پشتیبانی نمی‌شود.'; +$PHPMAILER_LANG['provide_address'] = 'باید حداقل یک آدرس گیرنده وارد کنید.'; +$PHPMAILER_LANG['recipients_failed'] = 'خطای SMTP: ارسال به آدرس گیرنده با خطا مواجه شد: '; +$PHPMAILER_LANG['signing'] = 'خطا در امضا: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'خطا در اتصال به SMTP.'; +$PHPMAILER_LANG['smtp_error'] = 'خطا در SMTP Server: '; +$PHPMAILER_LANG['variable_set'] = 'امکان ارسال یا ارسال مجدد متغیر‌ها وجود ندارد: '; +$PHPMAILER_LANG['extension_missing'] = 'افزونه موجود نیست: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php new file mode 100644 index 0000000000..6d1e637390 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP feilur: Kundi ikki góðkenna.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP feilur: Kundi ikki knýta samband við SMTP vert.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP feilur: Data ikki góðkent.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ókend encoding: '; +$PHPMAILER_LANG['execute'] = 'Kundi ikki útføra: '; +$PHPMAILER_LANG['file_access'] = 'Kundi ikki tilganga fílu: '; +$PHPMAILER_LANG['file_open'] = 'Fílu feilur: Kundi ikki opna fílu: '; +$PHPMAILER_LANG['from_failed'] = 'fylgjandi Frá/From adressa miseydnaðist: '; +$PHPMAILER_LANG['instantiate'] = 'Kuni ikki instantiera mail funktión.'; +//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' er ikki supporterað.'; +$PHPMAILER_LANG['provide_address'] = 'Tú skal uppgeva minst móttakara-emailadressu(r).'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feilur: Fylgjandi móttakarar miseydnaðust: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php new file mode 100644 index 0000000000..a6d582d833 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php @@ -0,0 +1,36 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro SMTP: Non puido ser autentificado.'; +$PHPMAILER_LANG['connect_host'] = 'Erro SMTP: Non puido conectar co servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro SMTP: Datos non aceptados.'; +$PHPMAILER_LANG['empty_message'] = 'Corpo da mensaxe vacía'; +$PHPMAILER_LANG['encoding'] = 'Codificación descoñecida: '; +$PHPMAILER_LANG['execute'] = 'Non puido ser executado: '; +$PHPMAILER_LANG['file_access'] = 'Nob puido acceder ó arquivo: '; +$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: No puido abrir o arquivo: '; +$PHPMAILER_LANG['from_failed'] = 'A(s) seguinte(s) dirección(s) de remitente(s) deron erro: '; +$PHPMAILER_LANG['instantiate'] = 'Non puido crear unha instancia da función Mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Non puido envia-lo correo: dirección de email inválida: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer non está soportado.'; +$PHPMAILER_LANG['provide_address'] = 'Debe engadir polo menos unha dirección de email coma destino.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro SMTP: Os seguintes destinos fallaron: '; +$PHPMAILER_LANG['signing'] = 'Erro ó firmar: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallou.'; +$PHPMAILER_LANG['smtp_error'] = 'Erro do servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Non puidemos axustar ou reaxustar a variábel: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php new file mode 100644 index 0000000000..b123aa5fc0 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'שגיאת SMTP: פעולת האימות נכשלה.'; +$PHPMAILER_LANG['connect_host'] = 'שגיאת SMTP: לא הצלחתי להתחבר לשרת SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'שגיאת SMTP: מידע לא התקבל.'; +$PHPMAILER_LANG['empty_message'] = 'גוף ההודעה ריק'; +$PHPMAILER_LANG['invalid_address'] = 'כתובת שגויה: '; +$PHPMAILER_LANG['encoding'] = 'קידוד לא מוכר: '; +$PHPMAILER_LANG['execute'] = 'לא הצלחתי להפעיל את: '; +$PHPMAILER_LANG['file_access'] = 'לא ניתן לגשת לקובץ: '; +$PHPMAILER_LANG['file_open'] = 'שגיאת קובץ: לא ניתן לגשת לקובץ: '; +$PHPMAILER_LANG['from_failed'] = 'כתובות הנמענים הבאות נכשלו: '; +$PHPMAILER_LANG['instantiate'] = 'לא הצלחתי להפעיל את פונקציית המייל.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' אינה נתמכת.'; +$PHPMAILER_LANG['provide_address'] = 'חובה לספק לפחות כתובת אחת של מקבל המייל.'; +$PHPMAILER_LANG['recipients_failed'] = 'שגיאת SMTP: הנמענים הבאים נכשלו: '; +$PHPMAILER_LANG['signing'] = 'שגיאת חתימה: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +$PHPMAILER_LANG['smtp_error'] = 'שגיאת שרת SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'לא ניתן לקבוע או לשנות את המשתנה: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hi.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hi.php new file mode 100644 index 0000000000..d2856e057b --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hi.php @@ -0,0 +1,35 @@ + + * Rewrite and extension of the work by Jayanti Suthar + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP त्रुटि: प्रामाणिकता की जांच नहीं हो सका। '; +$PHPMAILER_LANG['buggy_php'] = 'PHP का आपका संस्करण एक बग से प्रभावित है जिसके परिणामस्वरूप संदेश दूषित हो सकते हैं. इसे ठीक करने हेतु, भेजने के लिए SMTP का उपयोग करे, अपने php.ini में mail.add_x_header विकल्प को अक्षम करें, MacOS या Linux पर जाए, या अपने PHP संस्करण को 7.0.17+ या 7.1.3+ बदले.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP त्रुटि: SMTP सर्वर से कनेक्ट नहीं हो सका। '; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP त्रुटि: डेटा स्वीकार नहीं किया जाता है। '; +$PHPMAILER_LANG['empty_message'] = 'संदेश खाली है। '; +$PHPMAILER_LANG['encoding'] = 'अज्ञात एन्कोडिंग प्रकार। '; +$PHPMAILER_LANG['execute'] = 'आदेश को निष्पादित करने में विफल। '; +$PHPMAILER_LANG['extension_missing'] = 'एक्सटेन्षन गायब है: '; +$PHPMAILER_LANG['file_access'] = 'फ़ाइल उपलब्ध नहीं है। '; +$PHPMAILER_LANG['file_open'] = 'फ़ाइल त्रुटि: फाइल को खोला नहीं जा सका। '; +$PHPMAILER_LANG['from_failed'] = 'प्रेषक का पता गलत है। '; +$PHPMAILER_LANG['instantiate'] = 'मेल फ़ंक्शन कॉल नहीं कर सकता है।'; +$PHPMAILER_LANG['invalid_address'] = 'पता गलत है। '; +$PHPMAILER_LANG['invalid_header'] = 'अमान्य हेडर नाम या मान'; +$PHPMAILER_LANG['invalid_hostentry'] = 'अमान्य hostentry: '; +$PHPMAILER_LANG['invalid_host'] = 'अमान्य होस्ट: '; +$PHPMAILER_LANG['mailer_not_supported'] = 'मेल सर्वर के साथ काम नहीं करता है। '; +$PHPMAILER_LANG['provide_address'] = 'आपको कम से कम एक प्राप्तकर्ता का ई-मेल पता प्रदान करना होगा।'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP त्रुटि: निम्न प्राप्तकर्ताओं को पते भेजने में विफल। '; +$PHPMAILER_LANG['signing'] = 'साइनअप त्रुटि: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP कोड: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'अतिरिक्त SMTP जानकारी: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP का connect () फ़ंक्शन विफल हुआ। '; +$PHPMAILER_LANG['smtp_detail'] = 'विवरण: '; +$PHPMAILER_LANG['smtp_error'] = 'SMTP सर्वर त्रुटि। '; +$PHPMAILER_LANG['variable_set'] = 'चर को बना या संशोधित नहीं किया जा सकता। '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php new file mode 100644 index 0000000000..cacb6c37e5 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Greška: Neuspjela autentikacija.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Greška: Ne mogu se spojiti na SMTP poslužitelj.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Greška: Podatci nisu prihvaćeni.'; +$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznati encoding: '; +$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: '; +$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: '; +$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP Greška: Slanje s navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Greška: Slanje na navedenih e-mail adresa nije uspjelo: '; +$PHPMAILER_LANG['instantiate'] = 'Ne mogu pokrenuti mail funkcionalnost.'; +$PHPMAILER_LANG['invalid_address'] = 'E-mail nije poslan. Neispravna e-mail adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nije podržan.'; +$PHPMAILER_LANG['provide_address'] = 'Definirajte barem jednu adresu primatelja.'; +$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Spajanje na SMTP poslužitelj nije uspjelo.'; +$PHPMAILER_LANG['smtp_error'] = 'Greška SMTP poslužitelja: '; +$PHPMAILER_LANG['variable_set'] = 'Ne mogu postaviti varijablu niti ju vratiti nazad: '; +$PHPMAILER_LANG['extension_missing'] = 'Nedostaje proširenje: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php new file mode 100644 index 0000000000..e6b58b0dbe --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP -ի սխալ: չհաջողվեց ստուգել իսկությունը.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP -ի սխալ: չհաջողվեց կապ հաստատել SMTP սերվերի հետ.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP -ի սխալ: տվյալները ընդունված չեն.'; +$PHPMAILER_LANG['empty_message'] = 'Հաղորդագրությունը դատարկ է'; +$PHPMAILER_LANG['encoding'] = 'Կոդավորման անհայտ տեսակ: '; +$PHPMAILER_LANG['execute'] = 'Չհաջողվեց իրականացնել հրամանը: '; +$PHPMAILER_LANG['file_access'] = 'Ֆայլը հասանելի չէ: '; +$PHPMAILER_LANG['file_open'] = 'Ֆայլի սխալ: ֆայլը չհաջողվեց բացել: '; +$PHPMAILER_LANG['from_failed'] = 'Ուղարկողի հետևյալ հասցեն սխալ է: '; +$PHPMAILER_LANG['instantiate'] = 'Հնարավոր չէ կանչել mail ֆունկցիան.'; +$PHPMAILER_LANG['invalid_address'] = 'Հասցեն սխալ է: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' փոստային սերվերի հետ չի աշխատում.'; +$PHPMAILER_LANG['provide_address'] = 'Անհրաժեշտ է տրամադրել գոնե մեկ ստացողի e-mail հասցե.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP -ի սխալ: չի հաջողվել ուղարկել հետևյալ ստացողների հասցեներին: '; +$PHPMAILER_LANG['signing'] = 'Ստորագրման սխալ: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP -ի connect() ֆունկցիան չի հաջողվել'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP սերվերի սխալ: '; +$PHPMAILER_LANG['variable_set'] = 'Չի հաջողվում ստեղծել կամ վերափոխել փոփոխականը: '; +$PHPMAILER_LANG['extension_missing'] = 'Հավելվածը բացակայում է: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php new file mode 100644 index 0000000000..212a11f135 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php @@ -0,0 +1,31 @@ + + * @author @januridp + * @author Ian Mustafa + */ + +$PHPMAILER_LANG['authenticate'] = 'Kesalahan SMTP: Tidak dapat mengotentikasi.'; +$PHPMAILER_LANG['connect_host'] = 'Kesalahan SMTP: Tidak dapat terhubung ke host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Kesalahan SMTP: Data tidak diterima.'; +$PHPMAILER_LANG['empty_message'] = 'Isi pesan kosong'; +$PHPMAILER_LANG['encoding'] = 'Pengkodean karakter tidak dikenali: '; +$PHPMAILER_LANG['execute'] = 'Tidak dapat menjalankan proses: '; +$PHPMAILER_LANG['file_access'] = 'Tidak dapat mengakses berkas: '; +$PHPMAILER_LANG['file_open'] = 'Kesalahan Berkas: Berkas tidak dapat dibuka: '; +$PHPMAILER_LANG['from_failed'] = 'Alamat pengirim berikut mengakibatkan kesalahan: '; +$PHPMAILER_LANG['instantiate'] = 'Tidak dapat menginisialisasi fungsi surel.'; +$PHPMAILER_LANG['invalid_address'] = 'Gagal terkirim, alamat surel tidak sesuai: '; +$PHPMAILER_LANG['invalid_hostentry'] = 'Gagal terkirim, entri host tidak sesuai: '; +$PHPMAILER_LANG['invalid_host'] = 'Gagal terkirim, host tidak sesuai: '; +$PHPMAILER_LANG['provide_address'] = 'Harus tersedia minimal satu alamat tujuan'; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer tidak didukung'; +$PHPMAILER_LANG['recipients_failed'] = 'Kesalahan SMTP: Alamat tujuan berikut menyebabkan kesalahan: '; +$PHPMAILER_LANG['signing'] = 'Kesalahan dalam penandatangan SSL: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() gagal.'; +$PHPMAILER_LANG['smtp_error'] = 'Kesalahan pada pelayan SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Tidak dapat mengatur atau mengatur ulang variabel: '; +$PHPMAILER_LANG['extension_missing'] = 'Ekstensi PHP tidak tersedia: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php new file mode 100644 index 0000000000..08a6b73331 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php @@ -0,0 +1,28 @@ + + * @author Stefano Sabatini + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dati non accettati dal server.'; +$PHPMAILER_LANG['empty_message'] = 'Il corpo del messaggio è vuoto'; +$PHPMAILER_LANG['encoding'] = 'Codifica dei caratteri sconosciuta: '; +$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: '; +$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: '; +$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: '; +$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail'; +$PHPMAILER_LANG['invalid_address'] = 'Impossibile inviare, l\'indirizzo email non è valido: '; +$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato un errore: '; +$PHPMAILER_LANG['signing'] = 'Errore nella firma: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallita.'; +$PHPMAILER_LANG['smtp_error'] = 'Errore del server SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Impossibile impostare o resettare la variabile: '; +$PHPMAILER_LANG['extension_missing'] = 'Estensione mancante: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php new file mode 100644 index 0000000000..d01869cec8 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php @@ -0,0 +1,37 @@ + + * @author Yoshi Sakai + * @author Arisophy + * @author ARAKI Musashi + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTPエラー: 認証できませんでした。'; +$PHPMAILER_LANG['buggy_php'] = 'ご利用のバージョンのPHPには不具合があり、メッセージが破損するおそれがあります。問題の解決は以下のいずれかを行ってください。SMTPでの送信に切り替える。php.iniのmail.add_x_headerをoffにする。MacOSまたはLinuxに切り替える。PHPバージョン7.0.17以降または7.1.3以降にアップグレードする。'; +$PHPMAILER_LANG['connect_host'] = 'SMTPエラー: SMTPホストに接続できませんでした。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTPエラー: データが受け付けられませんでした。'; +$PHPMAILER_LANG['empty_message'] = 'メール本文が空です。'; +$PHPMAILER_LANG['encoding'] = '不明なエンコーディング: '; +$PHPMAILER_LANG['execute'] = '実行できませんでした: '; +$PHPMAILER_LANG['extension_missing'] = '拡張機能が見つかりません: '; +$PHPMAILER_LANG['file_access'] = 'ファイルにアクセスできません: '; +$PHPMAILER_LANG['file_open'] = 'ファイルエラー: ファイルを開けません: '; +$PHPMAILER_LANG['from_failed'] = 'Fromアドレスを登録する際にエラーが発生しました: '; +$PHPMAILER_LANG['instantiate'] = 'メール関数が正常に動作しませんでした。'; +$PHPMAILER_LANG['invalid_address'] = '不正なメールアドレス: '; +$PHPMAILER_LANG['invalid_header'] = '不正なヘッダー名またはその内容'; +$PHPMAILER_LANG['invalid_hostentry'] = '不正なホストエントリー: '; +$PHPMAILER_LANG['invalid_host'] = '不正なホスト: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' メーラーがサポートされていません。'; +$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレスに 間違いがあります: '; +$PHPMAILER_LANG['signing'] = '署名エラー: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTPコード: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'SMTP追加情報: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP接続に失敗しました。'; +$PHPMAILER_LANG['smtp_detail'] = '詳細: '; +$PHPMAILER_LANG['smtp_error'] = 'SMTPサーバーエラー: '; +$PHPMAILER_LANG['variable_set'] = '変数が存在しません: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php new file mode 100644 index 0000000000..51fe403b40 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP შეცდომა: ავტორიზაცია შეუძლებელია.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP შეცდომა: SMTP სერვერთან დაკავშირება შეუძლებელია.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP შეცდომა: მონაცემები არ იქნა მიღებული.'; +$PHPMAILER_LANG['encoding'] = 'კოდირების უცნობი ტიპი: '; +$PHPMAILER_LANG['execute'] = 'შეუძლებელია შემდეგი ბრძანების შესრულება: '; +$PHPMAILER_LANG['file_access'] = 'შეუძლებელია წვდომა ფაილთან: '; +$PHPMAILER_LANG['file_open'] = 'ფაილური სისტემის შეცდომა: არ იხსნება ფაილი: '; +$PHPMAILER_LANG['from_failed'] = 'გამგზავნის არასწორი მისამართი: '; +$PHPMAILER_LANG['instantiate'] = 'mail ფუნქციის გაშვება ვერ ხერხდება.'; +$PHPMAILER_LANG['provide_address'] = 'გთხოვთ მიუთითოთ ერთი ადრესატის e-mail მისამართი მაინც.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - საფოსტო სერვერის მხარდაჭერა არ არის.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP შეცდომა: შემდეგ მისამართებზე გაგზავნა ვერ მოხერხდა: '; +$PHPMAILER_LANG['empty_message'] = 'შეტყობინება ცარიელია'; +$PHPMAILER_LANG['invalid_address'] = 'არ გაიგზავნა, e-mail მისამართის არასწორი ფორმატი: '; +$PHPMAILER_LANG['signing'] = 'ხელმოწერის შეცდომა: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'შეცდომა SMTP სერვერთან დაკავშირებისას'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP სერვერის შეცდომა: '; +$PHPMAILER_LANG['variable_set'] = 'შეუძლებელია შემდეგი ცვლადის შექმნა ან შეცვლა: '; +$PHPMAILER_LANG['extension_missing'] = 'ბიბლიოთეკა არ არსებობს: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php new file mode 100644 index 0000000000..8c97dd947c --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 오류: 인증할 수 없습니다.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 오류: SMTP 호스트에 접속할 수 없습니다.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 오류: 데이터가 받아들여지지 않았습니다.'; +$PHPMAILER_LANG['empty_message'] = '메세지 내용이 없습니다'; +$PHPMAILER_LANG['encoding'] = '알 수 없는 인코딩: '; +$PHPMAILER_LANG['execute'] = '실행 불가: '; +$PHPMAILER_LANG['file_access'] = '파일 접근 불가: '; +$PHPMAILER_LANG['file_open'] = '파일 오류: 파일을 열 수 없습니다: '; +$PHPMAILER_LANG['from_failed'] = '다음 From 주소에서 오류가 발생했습니다: '; +$PHPMAILER_LANG['instantiate'] = 'mail 함수를 인스턴스화할 수 없습니다'; +$PHPMAILER_LANG['invalid_address'] = '잘못된 주소: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' 메일러는 지원되지 않습니다.'; +$PHPMAILER_LANG['provide_address'] = '적어도 한 개 이상의 수신자 메일 주소를 제공해야 합니다.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 오류: 다음 수신자에서 오류가 발생했습니다: '; +$PHPMAILER_LANG['signing'] = '서명 오류: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP 연결을 실패하였습니다.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP 서버 오류: '; +$PHPMAILER_LANG['variable_set'] = '변수 설정 및 초기화 불가: '; +$PHPMAILER_LANG['extension_missing'] = '확장자 없음: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ku.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ku.php new file mode 100644 index 0000000000..cf3bda69f2 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ku.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'هەڵەی SMTP : نەتوانرا کۆدەکە پشتڕاست بکرێتەوە '; +$PHPMAILER_LANG['connect_host'] = 'هەڵەی SMTP: نەتوانرا پەیوەندی بە سێرڤەرەوە بکات SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'هەڵەی SMTP: ئەو زانیاریانە قبوڵ نەکرا.'; +$PHPMAILER_LANG['empty_message'] = 'پەیامەکە بەتاڵە'; +$PHPMAILER_LANG['encoding'] = 'کۆدکردنی نەزانراو : '; +$PHPMAILER_LANG['execute'] = 'ناتوانرێت جێبەجێ بکرێت: '; +$PHPMAILER_LANG['file_access'] = 'ناتوانرێت دەستت بگات بە فایلەکە: '; +$PHPMAILER_LANG['file_open'] = 'هەڵەی پەڕگە(فایل): ناتوانرێت بکرێتەوە: '; +$PHPMAILER_LANG['from_failed'] = 'هەڵە لە ئاستی ناونیشانی نێرەر: '; +$PHPMAILER_LANG['instantiate'] = 'ناتوانرێت خزمەتگوزاری پۆستە پێشکەش بکرێت.'; +$PHPMAILER_LANG['invalid_address'] = 'نەتوانرا بنێردرێت ، چونکە ناونیشانی ئیمەیڵەکە نادروستە: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' مەیلەر پشتگیری ناکات'; +$PHPMAILER_LANG['provide_address'] = 'دەبێت ناونیشانی ئیمەیڵی لانیکەم یەک وەرگر دابین بکرێت.'; +$PHPMAILER_LANG['recipients_failed'] = ' هەڵەی SMTP: ئەم هەڵانەی خوارەوەشکستی هێنا لە ناردن بۆ هەردووکیان: '; +$PHPMAILER_LANG['signing'] = 'هەڵەی واژۆ: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect()پەیوەندی شکستی هێنا .'; +$PHPMAILER_LANG['smtp_error'] = 'هەڵەی ئاستی سێرڤەری SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'ناتوانرێت بیگۆڕیت یان دوبارە بینێریتەوە: '; +$PHPMAILER_LANG['extension_missing'] = 'درێژکراوە نەماوە: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php new file mode 100644 index 0000000000..4f115b1c58 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP klaida: autentifikacija nepavyko.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP klaida: nepavyksta prisijungti prie SMTP stoties.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP klaida: duomenys nepriimti.'; +$PHPMAILER_LANG['empty_message'] = 'Laiško turinys tuščias'; +$PHPMAILER_LANG['encoding'] = 'Neatpažinta koduotė: '; +$PHPMAILER_LANG['execute'] = 'Nepavyko įvykdyti komandos: '; +$PHPMAILER_LANG['file_access'] = 'Byla nepasiekiama: '; +$PHPMAILER_LANG['file_open'] = 'Bylos klaida: Nepavyksta atidaryti: '; +$PHPMAILER_LANG['from_failed'] = 'Neteisingas siuntėjo adresas: '; +$PHPMAILER_LANG['instantiate'] = 'Nepavyko paleisti mail funkcijos.'; +$PHPMAILER_LANG['invalid_address'] = 'Neteisingas adresas: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' pašto stotis nepalaikoma.'; +$PHPMAILER_LANG['provide_address'] = 'Nurodykite bent vieną gavėjo adresą.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP klaida: nepavyko išsiųsti šiems gavėjams: '; +$PHPMAILER_LANG['signing'] = 'Prisijungimo klaida: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP susijungimo klaida'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP stoties klaida: '; +$PHPMAILER_LANG['variable_set'] = 'Nepavyko priskirti reikšmės kintamajam: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php new file mode 100644 index 0000000000..679b18cf9f --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP kļūda: Autorizācija neizdevās.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Kļūda: Nevar izveidot savienojumu ar SMTP serveri.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Kļūda: Nepieņem informāciju.'; +$PHPMAILER_LANG['empty_message'] = 'Ziņojuma teksts ir tukšs'; +$PHPMAILER_LANG['encoding'] = 'Neatpazīts kodējums: '; +$PHPMAILER_LANG['execute'] = 'Neizdevās izpildīt komandu: '; +$PHPMAILER_LANG['file_access'] = 'Fails nav pieejams: '; +$PHPMAILER_LANG['file_open'] = 'Faila kļūda: Nevar atvērt failu: '; +$PHPMAILER_LANG['from_failed'] = 'Nepareiza sūtītāja adrese: '; +$PHPMAILER_LANG['instantiate'] = 'Nevar palaist sūtīšanas funkciju.'; +$PHPMAILER_LANG['invalid_address'] = 'Nepareiza adrese: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' sūtītājs netiek atbalstīts.'; +$PHPMAILER_LANG['provide_address'] = 'Lūdzu, norādiet vismaz vienu adresātu.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP kļūda: neizdevās nosūtīt šādiem saņēmējiem: '; +$PHPMAILER_LANG['signing'] = 'Autorizācijas kļūda: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP savienojuma kļūda'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP servera kļūda: '; +$PHPMAILER_LANG['variable_set'] = 'Nevar piešķirt mainīgā vērtību: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mg.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mg.php new file mode 100644 index 0000000000..8a94f6a044 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mg.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Hadisoana SMTP: Tsy nahomby ny fanamarinana.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Tsy afaka mampifandray amin\'ny mpampiantrano SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP diso: tsy voarakitra ny angona.'; +$PHPMAILER_LANG['empty_message'] = 'Tsy misy ny votoaty mailaka.'; +$PHPMAILER_LANG['encoding'] = 'Tsy fantatra encoding: '; +$PHPMAILER_LANG['execute'] = 'Tsy afaka manatanteraka ity baiko manaraka ity: '; +$PHPMAILER_LANG['file_access'] = 'Tsy nahomby ny fidirana amin\'ity rakitra ity: '; +$PHPMAILER_LANG['file_open'] = 'Hadisoana diso: Tsy afaka nanokatra ity file manaraka ity: '; +$PHPMAILER_LANG['from_failed'] = 'Ny adiresy iraka manaraka dia diso: '; +$PHPMAILER_LANG['instantiate'] = 'Tsy afaka nanomboka ny hetsika mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Tsy mety ny adiresy: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer tsy manohana.'; +$PHPMAILER_LANG['provide_address'] = 'Alefaso azafady iray adiresy iray farafahakeliny.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Tsy mety ireo mpanaraka ireto: '; +$PHPMAILER_LANG['signing'] = 'Error nandritra ny sonia:'; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Tsy nahomby ny fifandraisana tamin\'ny server SMTP.'; +$PHPMAILER_LANG['smtp_error'] = 'Fahadisoana tamin\'ny server SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Tsy azo atao ny mametraka na mamerina ny variable: '; +$PHPMAILER_LANG['extension_missing'] = 'Tsy hita ny ampahany: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mn.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mn.php new file mode 100644 index 0000000000..04d262c724 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-mn.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Ralat SMTP: Tidak dapat pengesahan.'; +$PHPMAILER_LANG['connect_host'] = 'Ralat SMTP: Tidak dapat menghubungi hos pelayan SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Ralat SMTP: Data tidak diterima oleh pelayan.'; +$PHPMAILER_LANG['empty_message'] = 'Tiada isi untuk mesej'; +$PHPMAILER_LANG['encoding'] = 'Pengekodan tidak diketahui: '; +$PHPMAILER_LANG['execute'] = 'Tidak dapat melaksanakan: '; +$PHPMAILER_LANG['file_access'] = 'Tidak dapat mengakses fail: '; +$PHPMAILER_LANG['file_open'] = 'Ralat Fail: Tidak dapat membuka fail: '; +$PHPMAILER_LANG['from_failed'] = 'Berikut merupakan ralat dari alamat e-mel: '; +$PHPMAILER_LANG['instantiate'] = 'Tidak dapat memberi contoh fungsi e-mel.'; +$PHPMAILER_LANG['invalid_address'] = 'Alamat emel tidak sah: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' jenis penghantar emel tidak disokong.'; +$PHPMAILER_LANG['provide_address'] = 'Anda perlu menyediakan sekurang-kurangnya satu alamat e-mel penerima.'; +$PHPMAILER_LANG['recipients_failed'] = 'Ralat SMTP: Penerima e-mel berikut telah gagal: '; +$PHPMAILER_LANG['signing'] = 'Ralat pada tanda tangan: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() telah gagal.'; +$PHPMAILER_LANG['smtp_error'] = 'Ralat pada pelayan SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Tidak boleh menetapkan atau menetapkan semula pembolehubah: '; +$PHPMAILER_LANG['extension_missing'] = 'Sambungan hilang: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php new file mode 100644 index 0000000000..c9621a164f --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php @@ -0,0 +1,33 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP-fout: authenticatie mislukt.'; +$PHPMAILER_LANG['buggy_php'] = 'PHP versie gededecteerd die onderhavig is aan een bug die kan resulteren in gecorrumpeerde berichten. Om dit te voorkomen, gebruik SMTP voor het verzenden van berichten, zet de mail.add_x_header optie in uw php.ini file uit, gebruik MacOS of Linux, of pas de gebruikte PHP versie aan naar versie 7.0.17+ or 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP-fout: kon niet verbinden met SMTP-host.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-fout: data niet geaccepteerd.'; +$PHPMAILER_LANG['empty_message'] = 'Berichttekst is leeg'; +$PHPMAILER_LANG['encoding'] = 'Onbekende codering: '; +$PHPMAILER_LANG['execute'] = 'Kon niet uitvoeren: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensie afwezig: '; +$PHPMAILER_LANG['file_access'] = 'Kreeg geen toegang tot bestand: '; +$PHPMAILER_LANG['file_open'] = 'Bestandsfout: kon bestand niet openen: '; +$PHPMAILER_LANG['from_failed'] = 'Het volgende afzendersadres is mislukt: '; +$PHPMAILER_LANG['instantiate'] = 'Kon mailfunctie niet initialiseren.'; +$PHPMAILER_LANG['invalid_address'] = 'Ongeldig adres: '; +$PHPMAILER_LANG['invalid_header'] = 'Ongeldige header naam of waarde'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Ongeldige hostentry: '; +$PHPMAILER_LANG['invalid_host'] = 'Ongeldige host: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.'; +$PHPMAILER_LANG['provide_address'] = 'Er moet minstens één ontvanger worden opgegeven.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP-fout: de volgende ontvangers zijn mislukt: '; +$PHPMAILER_LANG['signing'] = 'Signeerfout: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP code: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Aanvullende SMTP informatie: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Verbinding mislukt.'; +$PHPMAILER_LANG['smtp_detail'] = 'Detail: '; +$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfout: '; +$PHPMAILER_LANG['variable_set'] = 'Kan de volgende variabele niet instellen of resetten: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php new file mode 100644 index 0000000000..cb7b2c2107 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php @@ -0,0 +1,33 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro SMTP: Falha na autenticação.'; +$PHPMAILER_LANG['buggy_php'] = 'A sua versão do PHP tem um bug que pode causar mensagens corrompidas. Para resolver, utilize o envio por SMTP, desative a opção mail.add_x_header no ficheiro php.ini, mude para MacOS ou Linux, ou atualize o PHP para a versão 7.0.17+ ou 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'Erro SMTP: Não foi possível ligar ao servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro SMTP: Dados não aceites.'; +$PHPMAILER_LANG['empty_message'] = 'A mensagem de e-mail está vazia.'; +$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: '; +$PHPMAILER_LANG['execute'] = 'Não foi possível executar: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensão em falta: '; +$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder ao ficheiro: '; +$PHPMAILER_LANG['file_open'] = 'Erro ao abrir o ficheiro: '; +$PHPMAILER_LANG['from_failed'] = 'O envio falhou para o seguinte endereço do remetente: '; +$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: '; +$PHPMAILER_LANG['invalid_header'] = 'Nome ou valor do cabeçalho inválido.'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Entrada de host inválida: '; +$PHPMAILER_LANG['invalid_host'] = 'Host inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = 'O cliente de e-mail não é suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Deve fornecer pelo menos um endereço de destinatário.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro SMTP: Falha no envio para os seguintes destinatários: '; +$PHPMAILER_LANG['signing'] = 'Erro ao assinar: '; +$PHPMAILER_LANG['smtp_code'] = 'Código SMTP: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Informações adicionais SMTP: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Falha na função SMTP connect().'; +$PHPMAILER_LANG['smtp_detail'] = 'Detalhes: '; +$PHPMAILER_LANG['smtp_error'] = 'Erro do servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php new file mode 100644 index 0000000000..5239865a6f --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php @@ -0,0 +1,38 @@ + + * @author Lucas Guimarães + * @author Phelipe Alves + * @author Fabio Beneditto + * @author Geidson Benício Coelho + */ + +$PHPMAILER_LANG['authenticate'] = 'Erro de SMTP: Não foi possível autenticar.'; +$PHPMAILER_LANG['buggy_php'] = 'Sua versão do PHP é afetada por um bug que por resultar em messagens corrompidas. Para corrigir, mude para enviar usando SMTP, desative a opção mail.add_x_header em seu php.ini, mude para MacOS ou Linux, ou atualize seu PHP para versão 7.0.17+ ou 7.1.3+ '; +$PHPMAILER_LANG['connect_host'] = 'Erro de SMTP: Não foi possível conectar ao servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro de SMTP: Dados rejeitados.'; +$PHPMAILER_LANG['empty_message'] = 'Mensagem vazia'; +$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: '; +$PHPMAILER_LANG['execute'] = 'Não foi possível executar: '; +$PHPMAILER_LANG['extension_missing'] = 'Extensão não existe: '; +$PHPMAILER_LANG['file_access'] = 'Não foi possível acessar o arquivo: '; +$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: Não foi possível abrir o arquivo: '; +$PHPMAILER_LANG['from_failed'] = 'Os seguintes remetentes falharam: '; +$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: '; +$PHPMAILER_LANG['invalid_header'] = 'Nome ou valor de cabeçalho inválido'; +$PHPMAILER_LANG['invalid_hostentry'] = 'hostentry inválido: '; +$PHPMAILER_LANG['invalid_host'] = 'host inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Você deve informar pelo menos um destinatário.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro de SMTP: Os seguintes destinatários falharam: '; +$PHPMAILER_LANG['signing'] = 'Erro de Assinatura: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.'; +$PHPMAILER_LANG['smtp_code'] = 'Código do servidor SMTP: '; +$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Informações adicionais do servidor SMTP: '; +$PHPMAILER_LANG['smtp_detail'] = 'Detalhes do servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php new file mode 100644 index 0000000000..45bef91553 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php @@ -0,0 +1,33 @@ + + * @author Foster Snowhill + * @author ProjectSoft + */ + +$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: не удалось пройти аутентификацию.'; +$PHPMAILER_LANG['buggy_php'] = 'В вашей версии PHP есть ошибка, которая может привести к повреждению сообщений. Чтобы исправить, переключитесь на отправку по SMTP, отключите опцию mail.add_x_header в ваш php.ini, переключитесь на MacOS или Linux или обновите PHP до версии 7.0.17+ или 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к SMTP-серверу.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.'; +$PHPMAILER_LANG['empty_message'] = 'Пустое сообщение'; +$PHPMAILER_LANG['encoding'] = 'Неизвестная кодировка: '; +$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: '; +$PHPMAILER_LANG['extension_missing'] = 'Расширение отсутствует: '; +$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: '; +$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удаётся открыть файл: '; +$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: '; +$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail().'; +$PHPMAILER_LANG['invalid_address'] = 'Не отправлено из-за неправильного формата email-адреса: '; +$PHPMAILER_LANG['invalid_header'] = 'Неверное имя или значение заголовка'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Неверная запись хоста: '; +$PHPMAILER_LANG['invalid_host'] = 'Неверный хост: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' — почтовый сервер не поддерживается.'; +$PHPMAILER_LANG['provide_address'] = 'Вы должны указать хотя бы один адрес электронной почты получателя.'; +$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: Ошибка следующих получателей: '; +$PHPMAILER_LANG['signing'] = 'Ошибка подписи: '; +$PHPMAILER_LANG['smtp_code'] = 'Код SMTP: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Дополнительная информация SMTP: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ошибка соединения с SMTP-сервером.'; +$PHPMAILER_LANG['smtp_detail'] = 'Детали: '; +$PHPMAILER_LANG['smtp_error'] = 'Ошибка SMTP-сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Невозможно установить или сбросить переменную: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php new file mode 100644 index 0000000000..dce502aa02 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php @@ -0,0 +1,34 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP දෝෂය: සත්‍යාපනය අසාර්ථක විය.'; +$PHPMAILER_LANG['buggy_php'] = 'ඔබගේ PHP version එකෙහි පවතින දෝෂයක් නිසා email පණිවිඩ දෝෂ සහගත වීමේ හැකියාවක් ඇත. මෙය විසදීම සදහා SMTP භාවිතා කිරීම, mail.add_x_header INI setting එක අක්‍රීය කිරීම, MacOS හෝ Linux වලට මාරු වීම, හෝ ඔබගේ PHP version එක 7.0.17+ හෝ 7.1.3+ වලට අලුත් කිරීම කරගන්න.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP දෝෂය: සම්බන්ධ වීමට නොහැකි විය.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP දෝෂය: දත්ත පිළිගනු නොලැබේ.'; +$PHPMAILER_LANG['empty_message'] = 'පණිවිඩ අන්තර්ගතය හිස්'; +$PHPMAILER_LANG['encoding'] = 'නොදන්නා කේතනය: '; +$PHPMAILER_LANG['execute'] = 'ක්‍රියාත්මක කළ නොහැකි විය: '; +$PHPMAILER_LANG['extension_missing'] = 'Extension එක නොමැත: '; +$PHPMAILER_LANG['file_access'] = 'File එකට ප්‍රවේශ විය නොහැකි විය: '; +$PHPMAILER_LANG['file_open'] = 'File දෝෂය: File එක විවෘත කළ නොහැක: '; +$PHPMAILER_LANG['from_failed'] = 'පහත From ලිපිනයන් අසාර්ථක විය: '; +$PHPMAILER_LANG['instantiate'] = 'mail function එක ක්‍රියාත්මක කළ නොහැක.'; +$PHPMAILER_LANG['invalid_address'] = 'වලංගු නොවන ලිපිනය: '; +$PHPMAILER_LANG['invalid_header'] = 'වලංගු නොවන header නාමයක් හෝ අගයක්'; +$PHPMAILER_LANG['invalid_hostentry'] = 'වලංගු නොවන hostentry එකක්: '; +$PHPMAILER_LANG['invalid_host'] = 'වලංගු නොවන host එකක්: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer සහාය නොදක්වයි.'; +$PHPMAILER_LANG['provide_address'] = 'ඔබ අවම වශයෙන් එක් ලබන්නෙකුගේ ඊමේල් ලිපිනයක් සැපයිය යුතුය.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP දෝෂය: පහත ලබන්නන් අසමත් විය: '; +$PHPMAILER_LANG['signing'] = 'Sign කිරීමේ දෝෂය: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP කේතය: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'අමතර SMTP තොරතුරු: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP සම්බන්ධය අසාර්ථක විය.'; +$PHPMAILER_LANG['smtp_detail'] = 'තොරතුරු: '; +$PHPMAILER_LANG['smtp_error'] = 'SMTP දෝෂය: '; +$PHPMAILER_LANG['variable_set'] = 'Variable එක සැකසීමට හෝ නැවත සැකසීමට නොහැක: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php new file mode 100644 index 0000000000..028f5bc496 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php @@ -0,0 +1,30 @@ + + * @author Peter Orlický + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Chyba autentifikácie.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Nebolo možné nadviazať spojenie so SMTP serverom.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dáta neboli prijaté'; +$PHPMAILER_LANG['empty_message'] = 'Prázdne telo správy.'; +$PHPMAILER_LANG['encoding'] = 'Neznáme kódovanie: '; +$PHPMAILER_LANG['execute'] = 'Nedá sa vykonať: '; +$PHPMAILER_LANG['file_access'] = 'Súbor nebol nájdený: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Súbor sa otvoriť pre čítanie: '; +$PHPMAILER_LANG['from_failed'] = 'Následujúca adresa From je nesprávna: '; +$PHPMAILER_LANG['instantiate'] = 'Nedá sa vytvoriť inštancia emailovej funkcie.'; +$PHPMAILER_LANG['invalid_address'] = 'Neodoslané, emailová adresa je nesprávna: '; +$PHPMAILER_LANG['invalid_hostentry'] = 'Záznam hostiteľa je nesprávny: '; +$PHPMAILER_LANG['invalid_host'] = 'Hostiteľ je nesprávny: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' emailový klient nieje podporovaný.'; +$PHPMAILER_LANG['provide_address'] = 'Musíte zadať aspoň jednu emailovú adresu príjemcu.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Adresy príjemcov niesu správne '; +$PHPMAILER_LANG['signing'] = 'Chyba prihlasovania: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zlyhalo.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP chyba serveru: '; +$PHPMAILER_LANG['variable_set'] = 'Nemožno nastaviť alebo resetovať premennú: '; +$PHPMAILER_LANG['extension_missing'] = 'Chýba rozšírenie: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php new file mode 100644 index 0000000000..3e00c25963 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php @@ -0,0 +1,36 @@ + + * @author Filip Š + * @author Blaž Oražem + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP napaka: Avtentikacija ni uspela.'; +$PHPMAILER_LANG['buggy_php'] = 'Na vašo PHP različico vpliva napaka, ki lahko povzroči poškodovana sporočila. Če želite težavo odpraviti, preklopite na pošiljanje prek SMTP, onemogočite možnost mail.add_x_header v vaši php.ini datoteki, preklopite na MacOS ali Linux, ali nadgradite vašo PHP zaličico na 7.0.17+ ali 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP napaka: Vzpostavljanje povezave s SMTP gostiteljem ni uspelo.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP napaka: Strežnik zavrača podatke.'; +$PHPMAILER_LANG['empty_message'] = 'E-poštno sporočilo nima vsebine.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznan tip kodiranja: '; +$PHPMAILER_LANG['execute'] = 'Operacija ni uspela: '; +$PHPMAILER_LANG['extension_missing'] = 'Manjkajoča razširitev: '; +$PHPMAILER_LANG['file_access'] = 'Nimam dostopa do datoteke: '; +$PHPMAILER_LANG['file_open'] = 'Ne morem odpreti datoteke: '; +$PHPMAILER_LANG['from_failed'] = 'Neveljaven e-naslov pošiljatelja: '; +$PHPMAILER_LANG['instantiate'] = 'Ne morem inicializirati mail funkcije.'; +$PHPMAILER_LANG['invalid_address'] = 'E-poštno sporočilo ni bilo poslano. E-naslov je neveljaven: '; +$PHPMAILER_LANG['invalid_header'] = 'Neveljavno ime ali vrednost glave'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Neveljaven vnos gostitelja: '; +$PHPMAILER_LANG['invalid_host'] = 'Neveljaven gostitelj: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer ni podprt.'; +$PHPMAILER_LANG['provide_address'] = 'Prosimo, vnesite vsaj enega naslovnika.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP napaka: Sledeči naslovniki so neveljavni: '; +$PHPMAILER_LANG['signing'] = 'Napaka pri podpisovanju: '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP koda: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Dodatne informacije o SMTP: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ne morem vzpostaviti povezave s SMTP strežnikom.'; +$PHPMAILER_LANG['smtp_detail'] = 'Podrobnosti: '; +$PHPMAILER_LANG['smtp_error'] = 'Napaka SMTP strežnika: '; +$PHPMAILER_LANG['variable_set'] = 'Ne morem nastaviti oz. ponastaviti spremenljivke: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr.php new file mode 100644 index 0000000000..0b5280f75e --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr.php @@ -0,0 +1,28 @@ + + * @author Miloš Milanović + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP грешка: аутентификација није успела.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP грешка: повезивање са SMTP сервером није успело.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP грешка: подаци нису прихваћени.'; +$PHPMAILER_LANG['empty_message'] = 'Садржај поруке је празан.'; +$PHPMAILER_LANG['encoding'] = 'Непознато кодирање: '; +$PHPMAILER_LANG['execute'] = 'Није могуће извршити наредбу: '; +$PHPMAILER_LANG['file_access'] = 'Није могуће приступити датотеци: '; +$PHPMAILER_LANG['file_open'] = 'Није могуће отворити датотеку: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP грешка: слање са следећих адреса није успело: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP грешка: слање на следеће адресе није успело: '; +$PHPMAILER_LANG['instantiate'] = 'Није могуће покренути mail функцију.'; +$PHPMAILER_LANG['invalid_address'] = 'Порука није послата. Неисправна адреса: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' мејлер није подржан.'; +$PHPMAILER_LANG['provide_address'] = 'Дефинишите бар једну адресу примаоца.'; +$PHPMAILER_LANG['signing'] = 'Грешка приликом пријаве: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Повезивање са SMTP сервером није успело.'; +$PHPMAILER_LANG['smtp_error'] = 'Грешка SMTP сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Није могуће задати нити ресетовати променљиву: '; +$PHPMAILER_LANG['extension_missing'] = 'Недостаје проширење: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php new file mode 100644 index 0000000000..62138329ac --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php @@ -0,0 +1,28 @@ + + * @author Miloš Milanović + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP greška: autentifikacija nije uspela.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP greška: povezivanje sa SMTP serverom nije uspelo.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP greška: podaci nisu prihvaćeni.'; +$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.'; +$PHPMAILER_LANG['encoding'] = 'Nepoznato kodiranje: '; +$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: '; +$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: '; +$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: '; +$PHPMAILER_LANG['from_failed'] = 'SMTP greška: slanje sa sledećih adresa nije uspelo: '; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP greška: slanje na sledeće adrese nije uspelo: '; +$PHPMAILER_LANG['instantiate'] = 'Nije moguće pokrenuti mail funkciju.'; +$PHPMAILER_LANG['invalid_address'] = 'Poruka nije poslata. Neispravna adresa: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' majler nije podržan.'; +$PHPMAILER_LANG['provide_address'] = 'Definišite bar jednu adresu primaoca.'; +$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Povezivanje sa SMTP serverom nije uspelo.'; +$PHPMAILER_LANG['smtp_error'] = 'Greška SMTP servera: '; +$PHPMAILER_LANG['variable_set'] = 'Nije moguće zadati niti resetovati promenljivu: '; +$PHPMAILER_LANG['extension_missing'] = 'Nedostaje proširenje: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php new file mode 100644 index 0000000000..9872c19219 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fel: Kunde inte autentisera.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fel: Data accepterades inte.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Okänt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunde inte köra: '; +$PHPMAILER_LANG['file_access'] = 'Ingen åtkomst till fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte öppna fil: '; +$PHPMAILER_LANG['from_failed'] = 'Följande avsändaradress är felaktig: '; +$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.'; +$PHPMAILER_LANG['invalid_address'] = 'Felaktig adress: '; +$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: '; +$PHPMAILER_LANG['signing'] = 'Signeringsfel: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() misslyckades.'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP serverfel: '; +$PHPMAILER_LANG['variable_set'] = 'Kunde inte definiera eller återställa variabel: '; +$PHPMAILER_LANG['extension_missing'] = 'Tillägg ej tillgängligt: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tl.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tl.php new file mode 100644 index 0000000000..d15bed1c83 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tl.php @@ -0,0 +1,28 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Hindi mapatotohanan.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Hindi makakonekta sa SMTP host.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Ang datos ay hindi naitanggap.'; +$PHPMAILER_LANG['empty_message'] = 'Walang laman ang mensahe'; +$PHPMAILER_LANG['encoding'] = 'Hindi alam ang encoding: '; +$PHPMAILER_LANG['execute'] = 'Hindi maisasagawa: '; +$PHPMAILER_LANG['file_access'] = 'Hindi ma-access ang file: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Hindi mabuksan ang file: '; +$PHPMAILER_LANG['from_failed'] = 'Ang sumusunod na address ay nabigo: '; +$PHPMAILER_LANG['instantiate'] = 'Hindi maisimulan ang instance ng mail function.'; +$PHPMAILER_LANG['invalid_address'] = 'Hindi wasto ang address na naibigay: '; +$PHPMAILER_LANG['mailer_not_supported'] = 'Ang mailer ay hindi suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Kailangan mong magbigay ng kahit isang email address na tatanggap.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Ang mga sumusunod na tatanggap ay nabigo: '; +$PHPMAILER_LANG['signing'] = 'Hindi ma-sign: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Ang SMTP connect() ay nabigo.'; +$PHPMAILER_LANG['smtp_error'] = 'Ang server ng SMTP ay nabigo: '; +$PHPMAILER_LANG['variable_set'] = 'Hindi matatakda o ma-reset ang mga variables: '; +$PHPMAILER_LANG['extension_missing'] = 'Nawawala ang extension: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php new file mode 100644 index 0000000000..3c45bc1c35 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php @@ -0,0 +1,38 @@ + + * @fixed by Boris Yurchenko + */ + +$PHPMAILER_LANG['authenticate'] = 'Помилка SMTP: помилка авторизації.'; +$PHPMAILER_LANG['connect_host'] = 'Помилка SMTP: не вдається під\'єднатися до SMTP-серверу.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Помилка SMTP: дані не прийнято.'; +$PHPMAILER_LANG['encoding'] = 'Невідоме кодування: '; +$PHPMAILER_LANG['execute'] = 'Неможливо виконати команду: '; +$PHPMAILER_LANG['file_access'] = 'Немає доступу до файлу: '; +$PHPMAILER_LANG['file_open'] = 'Помилка файлової системи: не вдається відкрити файл: '; +$PHPMAILER_LANG['from_failed'] = 'Невірна адреса відправника: '; +$PHPMAILER_LANG['instantiate'] = 'Неможливо запустити функцію mail().'; +$PHPMAILER_LANG['provide_address'] = 'Будь ласка, введіть хоча б одну email-адресу отримувача.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - поштовий сервер не підтримується.'; +$PHPMAILER_LANG['recipients_failed'] = 'Помилка SMTP: не вдалося відправлення для таких отримувачів: '; +$PHPMAILER_LANG['empty_message'] = 'Пусте повідомлення'; +$PHPMAILER_LANG['invalid_address'] = 'Не відправлено через неправильний формат email-адреси: '; +$PHPMAILER_LANG['signing'] = 'Помилка підпису: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Помилка з\'єднання з SMTP-сервером'; +$PHPMAILER_LANG['smtp_error'] = 'Помилка SMTP-сервера: '; +$PHPMAILER_LANG['variable_set'] = 'Неможливо встановити або скинути змінну: '; +$PHPMAILER_LANG['extension_missing'] = 'Розширення відсутнє: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ur.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ur.php new file mode 100644 index 0000000000..0b9de0f127 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-ur.php @@ -0,0 +1,30 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP خرابی: تصدیق کرنے سے قاصر۔'; +$PHPMAILER_LANG['connect_host'] = 'SMTP خرابی: سرور سے منسلک ہونے سے قاصر۔'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP خرابی: ڈیٹا قبول نہیں کیا گیا۔'; +$PHPMAILER_LANG['empty_message'] = 'پیغام کی باڈی خالی ہے۔'; +$PHPMAILER_LANG['encoding'] = 'نامعلوم انکوڈنگ: '; +$PHPMAILER_LANG['execute'] = 'عمل کرنے کے قابل نہیں '; +$PHPMAILER_LANG['file_access'] = 'فائل تک رسائی سے قاصر:'; +$PHPMAILER_LANG['file_open'] = 'فائل کی خرابی: فائل کو کھولنے سے قاصر:'; +$PHPMAILER_LANG['from_failed'] = 'درج ذیل بھیجنے والے کا پتہ ناکام ہو گیا:'; +$PHPMAILER_LANG['instantiate'] = 'میل فنکشن کی مثال بنانے سے قاصر۔'; +$PHPMAILER_LANG['invalid_address'] = 'بھیجنے سے قاصر: غلط ای میل پتہ:'; +$PHPMAILER_LANG['mailer_not_supported'] = ' میلر تعاون یافتہ نہیں ہے۔'; +$PHPMAILER_LANG['provide_address'] = 'آپ کو کم از کم ایک منزل کا ای میل پتہ فراہم کرنا چاہیے۔'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP خرابی: درج ذیل پتہ پر نہیں بھیجا جاسکا: '; +$PHPMAILER_LANG['signing'] = 'دستخط کی خرابی: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP ملنا ناکام ہوا'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP سرور کی خرابی: '; +$PHPMAILER_LANG['variable_set'] = 'متغیر سیٹ نہیں کیا جا سکا: '; +$PHPMAILER_LANG['extension_missing'] = 'ایکٹینشن موجود نہیں ہے۔ '; +$PHPMAILER_LANG['smtp_code'] = 'SMTP سرور کوڈ: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'اضافی SMTP سرور کی معلومات:'; +$PHPMAILER_LANG['invalid_header'] = 'غلط ہیڈر کا نام یا قدر'; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php new file mode 100644 index 0000000000..d65576e2d4 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php @@ -0,0 +1,27 @@ + + */ + +$PHPMAILER_LANG['authenticate'] = 'Lỗi SMTP: Không thể xác thực.'; +$PHPMAILER_LANG['connect_host'] = 'Lỗi SMTP: Không thể kết nối máy chủ SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Lỗi SMTP: Dữ liệu không được chấp nhận.'; +$PHPMAILER_LANG['empty_message'] = 'Không có nội dung'; +$PHPMAILER_LANG['encoding'] = 'Mã hóa không xác định: '; +$PHPMAILER_LANG['execute'] = 'Không thực hiện được: '; +$PHPMAILER_LANG['file_access'] = 'Không thể truy cập tệp tin '; +$PHPMAILER_LANG['file_open'] = 'Lỗi Tập tin: Không thể mở tệp tin: '; +$PHPMAILER_LANG['from_failed'] = 'Lỗi địa chỉ gửi đi: '; +$PHPMAILER_LANG['instantiate'] = 'Không dùng được các hàm gửi thư.'; +$PHPMAILER_LANG['invalid_address'] = 'Đại chỉ emai không đúng: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' trình gửi thư không được hỗ trợ.'; +$PHPMAILER_LANG['provide_address'] = 'Bạn phải cung cấp ít nhất một địa chỉ người nhận.'; +$PHPMAILER_LANG['recipients_failed'] = 'Lỗi SMTP: lỗi địa chỉ người nhận: '; +$PHPMAILER_LANG['signing'] = 'Lỗi đăng nhập: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Lỗi kết nối với SMTP'; +$PHPMAILER_LANG['smtp_error'] = 'Lỗi máy chủ smtp '; +$PHPMAILER_LANG['variable_set'] = 'Không thể thiết lập hoặc thiết lập lại biến: '; +//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php new file mode 100644 index 0000000000..35e4e7000e --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php @@ -0,0 +1,29 @@ + + * @author Peter Dave Hello <@PeterDaveHello/> + * @author Jason Chiang + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 錯誤:登入失敗。'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 錯誤:無法連線到 SMTP 主機。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 錯誤:無法接受的資料。'; +$PHPMAILER_LANG['empty_message'] = '郵件內容為空'; +$PHPMAILER_LANG['encoding'] = '未知編碼: '; +$PHPMAILER_LANG['execute'] = '無法執行:'; +$PHPMAILER_LANG['file_access'] = '無法存取檔案:'; +$PHPMAILER_LANG['file_open'] = '檔案錯誤:無法開啟檔案:'; +$PHPMAILER_LANG['from_failed'] = '發送地址錯誤:'; +$PHPMAILER_LANG['instantiate'] = '未知函數呼叫。'; +$PHPMAILER_LANG['invalid_address'] = '因為電子郵件地址無效,無法傳送: '; +$PHPMAILER_LANG['mailer_not_supported'] = '不支援的發信客戶端。'; +$PHPMAILER_LANG['provide_address'] = '必須提供至少一個收件人地址。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 錯誤:以下收件人地址錯誤:'; +$PHPMAILER_LANG['signing'] = '電子簽章錯誤: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP 連線失敗'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP 伺服器錯誤: '; +$PHPMAILER_LANG['variable_set'] = '無法設定或重設變數: '; +$PHPMAILER_LANG['extension_missing'] = '遺失模組 Extension: '; diff --git a/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php new file mode 100644 index 0000000000..03d491165b --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php @@ -0,0 +1,36 @@ + + * @author young + * @author Teddysun + */ + +$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:登录失败。'; +$PHPMAILER_LANG['buggy_php'] = '您的 PHP 版本存在漏洞,可能会导致消息损坏。为修复此问题,请切换到使用 SMTP 发送,在您的 php.ini 中禁用 mail.add_x_header 选项。切换到 MacOS 或 Linux,或将您的 PHP 升级到 7.0.17+ 或 7.1.3+ 版本。'; +$PHPMAILER_LANG['connect_host'] = 'SMTP 错误:无法连接到 SMTP 主机。'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误:数据不被接受。'; +$PHPMAILER_LANG['empty_message'] = '邮件正文为空。'; +$PHPMAILER_LANG['encoding'] = '未知编码:'; +$PHPMAILER_LANG['execute'] = '无法执行:'; +$PHPMAILER_LANG['extension_missing'] = '缺少扩展名:'; +$PHPMAILER_LANG['file_access'] = '无法访问文件:'; +$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:'; +$PHPMAILER_LANG['from_failed'] = '发送地址错误:'; +$PHPMAILER_LANG['instantiate'] = '未知函数调用。'; +$PHPMAILER_LANG['invalid_address'] = '发送失败,电子邮箱地址是无效的:'; +$PHPMAILER_LANG['mailer_not_supported'] = '发信客户端不被支持。'; +$PHPMAILER_LANG['provide_address'] = '必须提供至少一个收件人地址。'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:'; +$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP服务器连接失败。'; +$PHPMAILER_LANG['smtp_error'] = 'SMTP服务器出错:'; +$PHPMAILER_LANG['variable_set'] = '无法设置或重置变量:'; +$PHPMAILER_LANG['invalid_header'] = '无效的标题名称或值'; +$PHPMAILER_LANG['invalid_hostentry'] = '无效的hostentry: '; +$PHPMAILER_LANG['invalid_host'] = '无效的主机:'; +$PHPMAILER_LANG['signing'] = '签名错误:'; +$PHPMAILER_LANG['smtp_code'] = 'SMTP代码: '; +$PHPMAILER_LANG['smtp_code_ex'] = '附加SMTP信息: '; +$PHPMAILER_LANG['smtp_detail'] = '详情:'; diff --git a/lib/vendor/phpmailer/phpmailer/src/DSNConfigurator.php b/lib/vendor/phpmailer/phpmailer/src/DSNConfigurator.php new file mode 100644 index 0000000000..7058c1f05e --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/src/DSNConfigurator.php @@ -0,0 +1,245 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2023 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * Configure PHPMailer with DSN string. + * + * @see https://en.wikipedia.org/wiki/Data_source_name + * + * @author Oleg Voronkovich + */ +class DSNConfigurator +{ + /** + * Create new PHPMailer instance configured by DSN. + * + * @param string $dsn DSN + * @param bool $exceptions Should we throw external exceptions? + * + * @return PHPMailer + */ + public static function mailer($dsn, $exceptions = null) + { + static $configurator = null; + + if (null === $configurator) { + $configurator = new DSNConfigurator(); + } + + return $configurator->configure(new PHPMailer($exceptions), $dsn); + } + + /** + * Configure PHPMailer instance with DSN string. + * + * @param PHPMailer $mailer PHPMailer instance + * @param string $dsn DSN + * + * @return PHPMailer + */ + public function configure(PHPMailer $mailer, $dsn) + { + $config = $this->parseDSN($dsn); + + $this->applyConfig($mailer, $config); + + return $mailer; + } + + /** + * Parse DSN string. + * + * @param string $dsn DSN + * + * @throws Exception If DSN is malformed + * + * @return array Configuration + */ + private function parseDSN($dsn) + { + $config = $this->parseUrl($dsn); + + if (false === $config || !isset($config['scheme']) || !isset($config['host'])) { + throw new Exception('Malformed DSN'); + } + + if (isset($config['query'])) { + parse_str($config['query'], $config['query']); + } + + return $config; + } + + /** + * Apply configuration to mailer. + * + * @param PHPMailer $mailer PHPMailer instance + * @param array $config Configuration + * + * @throws Exception If scheme is invalid + */ + private function applyConfig(PHPMailer $mailer, $config) + { + switch ($config['scheme']) { + case 'mail': + $mailer->isMail(); + break; + case 'sendmail': + $mailer->isSendmail(); + break; + case 'qmail': + $mailer->isQmail(); + break; + case 'smtp': + case 'smtps': + $mailer->isSMTP(); + $this->configureSMTP($mailer, $config); + break; + default: + throw new Exception( + sprintf( + 'Invalid scheme: "%s". Allowed values: "mail", "sendmail", "qmail", "smtp", "smtps".', + $config['scheme'] + ) + ); + } + + if (isset($config['query'])) { + $this->configureOptions($mailer, $config['query']); + } + } + + /** + * Configure SMTP. + * + * @param PHPMailer $mailer PHPMailer instance + * @param array $config Configuration + */ + private function configureSMTP($mailer, $config) + { + $isSMTPS = 'smtps' === $config['scheme']; + + if ($isSMTPS) { + $mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; + } + + $mailer->Host = $config['host']; + + if (isset($config['port'])) { + $mailer->Port = $config['port']; + } elseif ($isSMTPS) { + $mailer->Port = SMTP::DEFAULT_SECURE_PORT; + } + + $mailer->SMTPAuth = isset($config['user']) || isset($config['pass']); + + if (isset($config['user'])) { + $mailer->Username = $config['user']; + } + + if (isset($config['pass'])) { + $mailer->Password = $config['pass']; + } + } + + /** + * Configure options. + * + * @param PHPMailer $mailer PHPMailer instance + * @param array $options Options + * + * @throws Exception If option is unknown + */ + private function configureOptions(PHPMailer $mailer, $options) + { + $allowedOptions = get_object_vars($mailer); + + unset($allowedOptions['Mailer']); + unset($allowedOptions['SMTPAuth']); + unset($allowedOptions['Username']); + unset($allowedOptions['Password']); + unset($allowedOptions['Hostname']); + unset($allowedOptions['Port']); + unset($allowedOptions['ErrorInfo']); + + $allowedOptions = \array_keys($allowedOptions); + + foreach ($options as $key => $value) { + if (!in_array($key, $allowedOptions)) { + throw new Exception( + sprintf( + 'Unknown option: "%s". Allowed values: "%s"', + $key, + implode('", "', $allowedOptions) + ) + ); + } + + switch ($key) { + case 'AllowEmpty': + case 'SMTPAutoTLS': + case 'SMTPKeepAlive': + case 'SingleTo': + case 'UseSendmailOptions': + case 'do_verp': + case 'DKIM_copyHeaderFields': + $mailer->$key = (bool) $value; + break; + case 'Priority': + case 'SMTPDebug': + case 'WordWrap': + $mailer->$key = (int) $value; + break; + default: + $mailer->$key = $value; + break; + } + } + } + + /** + * Parse a URL. + * Wrapper for the built-in parse_url function to work around a bug in PHP 5.5. + * + * @param string $url URL + * + * @return array|false + */ + protected function parseUrl($url) + { + if (\PHP_VERSION_ID >= 50600 || false === strpos($url, '?')) { + return parse_url($url); + } + + $chunks = explode('?', $url); + if (is_array($chunks)) { + $result = parse_url($chunks[0]); + if (is_array($result)) { + $result['query'] = $chunks[1]; + } + return $result; + } + + return false; + } +} diff --git a/lib/vendor/phpmailer/phpmailer/src/Exception.php b/lib/vendor/phpmailer/phpmailer/src/Exception.php new file mode 100644 index 0000000000..09c1a2cfef --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/src/Exception.php @@ -0,0 +1,40 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2020 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer exception handler. + * + * @author Marcus Bointon + */ +class Exception extends \Exception +{ + /** + * Prettify error message output. + * + * @return string + */ + public function errorMessage() + { + return '' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "
      \n"; + } +} diff --git a/lib/vendor/phpmailer/phpmailer/src/OAuth.php b/lib/vendor/phpmailer/phpmailer/src/OAuth.php new file mode 100644 index 0000000000..a7e958860c --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/src/OAuth.php @@ -0,0 +1,139 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2020 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +use League\OAuth2\Client\Grant\RefreshToken; +use League\OAuth2\Client\Provider\AbstractProvider; +use League\OAuth2\Client\Token\AccessToken; + +/** + * OAuth - OAuth2 authentication wrapper class. + * Uses the oauth2-client package from the League of Extraordinary Packages. + * + * @see https://oauth2-client.thephpleague.com + * + * @author Marcus Bointon (Synchro/coolbru) + */ +class OAuth implements OAuthTokenProvider +{ + /** + * An instance of the League OAuth Client Provider. + * + * @var AbstractProvider + */ + protected $provider; + + /** + * The current OAuth access token. + * + * @var AccessToken + */ + protected $oauthToken; + + /** + * The user's email address, usually used as the login ID + * and also the from address when sending email. + * + * @var string + */ + protected $oauthUserEmail = ''; + + /** + * The client secret, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientSecret = ''; + + /** + * The client ID, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientId = ''; + + /** + * The refresh token, used to obtain new AccessTokens. + * + * @var string + */ + protected $oauthRefreshToken = ''; + + /** + * OAuth constructor. + * + * @param array $options Associative array containing + * `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements + */ + public function __construct($options) + { + $this->provider = $options['provider']; + $this->oauthUserEmail = $options['userName']; + $this->oauthClientSecret = $options['clientSecret']; + $this->oauthClientId = $options['clientId']; + $this->oauthRefreshToken = $options['refreshToken']; + } + + /** + * Get a new RefreshToken. + * + * @return RefreshToken + */ + protected function getGrant() + { + return new RefreshToken(); + } + + /** + * Get a new AccessToken. + * + * @return AccessToken + */ + protected function getToken() + { + return $this->provider->getAccessToken( + $this->getGrant(), + ['refresh_token' => $this->oauthRefreshToken] + ); + } + + /** + * Generate a base64-encoded OAuth token. + * + * @return string + */ + public function getOauth64() + { + //Get a new token if it's not available or has expired + if (null === $this->oauthToken || $this->oauthToken->hasExpired()) { + $this->oauthToken = $this->getToken(); + } + + return base64_encode( + 'user=' . + $this->oauthUserEmail . + "\001auth=Bearer " . + $this->oauthToken . + "\001\001" + ); + } +} diff --git a/lib/vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php b/lib/vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php new file mode 100644 index 0000000000..cbda1a1296 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php @@ -0,0 +1,44 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2020 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * OAuthTokenProvider - OAuth2 token provider interface. + * Provides base64 encoded OAuth2 auth strings for SMTP authentication. + * + * @see OAuth + * @see SMTP::authenticate() + * + * @author Peter Scopes (pdscopes) + * @author Marcus Bointon (Synchro/coolbru) + */ +interface OAuthTokenProvider +{ + /** + * Generate a base64-encoded OAuth token ensuring that the access token has not expired. + * The string to be base 64 encoded should be in the form: + * "user=\001auth=Bearer \001\001" + * + * @return string + */ + public function getOauth64(); +} diff --git a/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php b/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php new file mode 100644 index 0000000000..2444bcf351 --- /dev/null +++ b/lib/vendor/phpmailer/phpmailer/src/PHPMailer.php @@ -0,0 +1,5362 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2020 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer - PHP email creation and transport class. + * + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + const CHARSET_ASCII = 'us-ascii'; + const CHARSET_ISO88591 = 'iso-8859-1'; + const CHARSET_UTF8 = 'utf-8'; + + const CONTENT_TYPE_PLAINTEXT = 'text/plain'; + const CONTENT_TYPE_TEXT_CALENDAR = 'text/calendar'; + const CONTENT_TYPE_TEXT_HTML = 'text/html'; + const CONTENT_TYPE_MULTIPART_ALTERNATIVE = 'multipart/alternative'; + const CONTENT_TYPE_MULTIPART_MIXED = 'multipart/mixed'; + const CONTENT_TYPE_MULTIPART_RELATED = 'multipart/related'; + + const ENCODING_7BIT = '7bit'; + const ENCODING_8BIT = '8bit'; + const ENCODING_BASE64 = 'base64'; + const ENCODING_BINARY = 'binary'; + const ENCODING_QUOTED_PRINTABLE = 'quoted-printable'; + + const ENCRYPTION_STARTTLS = 'tls'; + const ENCRYPTION_SMTPS = 'ssl'; + + const ICAL_METHOD_REQUEST = 'REQUEST'; + const ICAL_METHOD_PUBLISH = 'PUBLISH'; + const ICAL_METHOD_REPLY = 'REPLY'; + const ICAL_METHOD_ADD = 'ADD'; + const ICAL_METHOD_CANCEL = 'CANCEL'; + const ICAL_METHOD_REFRESH = 'REFRESH'; + const ICAL_METHOD_COUNTER = 'COUNTER'; + const ICAL_METHOD_DECLINECOUNTER = 'DECLINECOUNTER'; + + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * + * @var int|null + */ + public $Priority; + + /** + * The character set of the message. + * + * @var string + */ + public $CharSet = self::CHARSET_ISO88591; + + /** + * The MIME Content-type of the message. + * + * @var string + */ + public $ContentType = self::CONTENT_TYPE_PLAINTEXT; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * + * @var string + */ + public $Encoding = self::ENCODING_8BIT; + + /** + * Holds the most recent mailer error message. + * + * @var string + */ + public $ErrorInfo = ''; + + /** + * The From email address for the message. + * + * @var string + */ + public $From = ''; + + /** + * The From name of the message. + * + * @var string + */ + public $FromName = ''; + + /** + * The envelope sender of the message. + * This will usually be turned into a Return-Path header by the receiver, + * and is the address that bounces will be sent to. + * If not empty, will be passed via `-f` to sendmail or as the 'MAIL FROM' value over SMTP. + * + * @var string + */ + public $Sender = ''; + + /** + * The Subject of the message. + * + * @var string + */ + public $Subject = ''; + + /** + * An HTML or plain text message body. + * If HTML then call isHTML(true). + * + * @var string + */ + public $Body = ''; + + /** + * The plain-text message body. + * This body can be read by mail clients that do not have HTML email + * capability such as mutt & Eudora. + * Clients that can read HTML will view the normal Body. + * + * @var string + */ + public $AltBody = ''; + + /** + * An iCal message part body. + * Only supported in simple alt or alt_inline message types + * To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator. + * + * @see https://kigkonsult.se/iCalcreator/ + * + * @var string + */ + public $Ical = ''; + + /** + * Value-array of "method" in Contenttype header "text/calendar" + * + * @var string[] + */ + protected static $IcalMethods = [ + self::ICAL_METHOD_REQUEST, + self::ICAL_METHOD_PUBLISH, + self::ICAL_METHOD_REPLY, + self::ICAL_METHOD_ADD, + self::ICAL_METHOD_CANCEL, + self::ICAL_METHOD_REFRESH, + self::ICAL_METHOD_COUNTER, + self::ICAL_METHOD_DECLINECOUNTER, + ]; + + /** + * The complete compiled MIME message body. + * + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * + * @var string + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * + * @var string + */ + protected $mailHeader = ''; + + /** + * Word-wrap the message body to this number of chars. + * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. + * + * @see static::STD_LINE_LENGTH + * + * @var int + */ + public $WordWrap = 0; + + /** + * Which method to use to send mail. + * Options: "mail", "sendmail", or "smtp". + * + * @var string + */ + public $Mailer = 'mail'; + + /** + * The path to the sendmail program. + * + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + /** + * Whether mail() uses a fully sendmail-compatible MTA. + * One which supports sendmail's "-oi -f" options. + * + * @var bool + */ + public $UseSendmailOptions = true; + + /** + * The email address that a reading confirmation should be sent to, also known as read receipt. + * + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * The hostname to use in the Message-ID header and as default HELO string. + * If empty, PHPMailer attempts to find one with, in order, + * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value + * 'localhost.localdomain'. + * + * @see PHPMailer::$Helo + * + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * You can set your own, but it must be in the format "", + * as defined in RFC5322 section 3.6.4 or it will be ignored. + * + * @see https://www.rfc-editor.org/rfc/rfc5322#section-3.6.4 + * + * @var string + */ + public $MessageID = ''; + + /** + * The message Date to be used in the Date header. + * If empty, the current date will be added. + * + * @var string + */ + public $MessageDate = ''; + + /** + * SMTP hosts. + * Either a single hostname or multiple semicolon-delimited hostnames. + * You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * You can also specify encryption type, for example: + * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). + * Hosts will be tried in order. + * + * @var string + */ + public $Host = 'localhost'; + + /** + * The default SMTP server port. + * + * @var int + */ + public $Port = 25; + + /** + * The SMTP HELO/EHLO name used for the SMTP connection. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * + * @see PHPMailer::$Hostname + * + * @var string + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', static::ENCRYPTION_STARTTLS, or static::ENCRYPTION_SMTPS. + * + * @var string + */ + public $SMTPSecure = ''; + + /** + * Whether to enable TLS encryption automatically if a server supports it, + * even if `SMTPSecure` is not set to 'tls'. + * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. + * + * @var bool + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * + * @see PHPMailer::$Username + * @see PHPMailer::$Password + * + * @var bool + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * + * @var array + */ + public $SMTPOptions = []; + + /** + * SMTP username. + * + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * + * @var string + */ + public $Password = ''; + + /** + * SMTP authentication type. Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2. + * If not specified, the first one from that list that the server supports will be selected. + * + * @var string + */ + public $AuthType = ''; + + /** + * SMTP SMTPXClient command attributes + * + * @var array + */ + protected $SMTPXClient = []; + + /** + * An implementation of the PHPMailer OAuthTokenProvider interface. + * + * @var OAuthTokenProvider + */ + protected $oauth; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timeout = 300; + + /** + * Comma separated list of DSN notifications + * 'NEVER' under no circumstances a DSN must be returned to the sender. + * If you use NEVER all other notifications will be ignored. + * 'SUCCESS' will notify you when your mail has arrived at its destination. + * 'FAILURE' will arrive if an error occurred during delivery. + * 'DELAY' will notify you if there is an unusual delay in delivery, but the actual + * delivery's outcome (success or failure) is not yet decided. + * + * @see https://www.rfc-editor.org/rfc/rfc3461.html#section-4.1 for more information about NOTIFY + */ + public $dsn = ''; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * @see SMTP::DEBUG_OFF: No output + * @see SMTP::DEBUG_CLIENT: Client messages + * @see SMTP::DEBUG_SERVER: Client and server messages + * @see SMTP::DEBUG_CONNECTION: As SERVER plus connection status + * @see SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed + * + * @see SMTP::$do_debug + * + * @var int + */ + public $SMTPDebug = 0; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
      `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise. + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @see SMTP::$Debugoutput + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to keep the SMTP connection open after each message. + * If this is set to true then the connection will remain open after a send, + * and closing the connection will require an explicit call to smtpClose(). + * It's a good idea to use this if you are sending multiple messages as it reduces overhead. + * See the mailing list example for how to use it. + * + * @var bool + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * Only supported in `mail` and `sendmail` transports, not in SMTP. + * + * @var bool + * + * @deprecated 6.0.0 PHPMailer isn't a mailing list manager! + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * + * @var array + */ + protected $SingleToArray = []; + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * + * @see https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see https://www.postfix.org/VERP_README.html Postfix VERP info + * + * @var bool + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * + * @var bool + */ + public $AllowEmpty = false; + + /** + * DKIM selector. + * + * @var string + */ + public $DKIM_selector = ''; + + /** + * DKIM Identity. + * Usually the email address used as the source of the email. + * + * @var string + */ + public $DKIM_identity = ''; + + /** + * DKIM passphrase. + * Used if your key is encrypted. + * + * @var string + */ + public $DKIM_passphrase = ''; + + /** + * DKIM signing domain name. + * + * @example 'example.com' + * + * @var string + */ + public $DKIM_domain = ''; + + /** + * DKIM Copy header field values for diagnostic use. + * + * @var bool + */ + public $DKIM_copyHeaderFields = true; + + /** + * DKIM Extra signing headers. + * + * @example ['List-Unsubscribe', 'List-Help'] + * + * @var array + */ + public $DKIM_extraHeaders = []; + + /** + * DKIM private key file path. + * + * @var string + */ + public $DKIM_private = ''; + + /** + * DKIM private key string. + * + * If set, takes precedence over `$DKIM_private`. + * + * @var string + */ + public $DKIM_private_string = ''; + + /** + * Callback Action function name. + * + * The function that handles the result of the send email action. + * It is called out by send() for each email sent. + * + * Value can be any php callable: https://www.php.net/is_callable + * + * Parameters: + * bool $result result of the send action + * array $to email addresses of the recipients + * array $cc cc email addresses + * array $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * string $extra extra information of possible use + * "smtp_transaction_id' => last smtp transaction id + * + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace/null for none, or a string to use. + * + * @var string|null + */ + public $XMailer = ''; + + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option. + * + * If CharSet is UTF8, the validator is left at the default value, + * and you send to addresses that use non-ASCII local parts, then + * PHPMailer automatically changes to the 'eai' validator. + * + * @see PHPMailer::validateAddress() + * + * @var string|callable + */ + public static $validator = 'php'; + + /** + * An instance of the SMTP sender class. + * + * @var SMTP + */ + protected $smtp; + + /** + * The array of 'to' names and addresses. + * + * @var array + */ + protected $to = []; + + /** + * The array of 'cc' names and addresses. + * + * @var array + */ + protected $cc = []; + + /** + * The array of 'bcc' names and addresses. + * + * @var array + */ + protected $bcc = []; + + /** + * The array of reply-to names and addresses. + * + * @var array + */ + protected $ReplyTo = []; + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * + * @var array + */ + protected $all_recipients = []; + + /** + * An array of names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $all_recipients + * and one of $to, $cc, or $bcc. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + * + * @var array + */ + protected $RecipientsQueue = []; + + /** + * An array of reply-to names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $ReplyTo. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$ReplyTo + * + * @var array + */ + protected $ReplyToQueue = []; + + /** + * Whether the need for SMTPUTF8 has been detected. Set by + * preSend() if necessary. + * + * @var bool + */ + public $UseSMTPUTF8 = false; + + /** + * The array of attachments. + * + * @var array + */ + protected $attachment = []; + + /** + * The array of custom headers. + * + * @var array + */ + protected $CustomHeader = []; + + /** + * The most recent Message-ID (including angular brackets). + * + * @var string + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * + * @var string + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * + * @var array + */ + protected $boundary = []; + + /** + * The array of available text strings for the current language. + * + * @var array + */ + protected $language = []; + + /** + * The number of errors encountered. + * + * @var int + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * + * @var string + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * + * @var string + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * + * @var string + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * + * @var string + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * + * @var bool + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * + * @var string + */ + protected $uniqueid = ''; + + /** + * The PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.10.0'; + + /** + * Error severity: message only, continue processing. + * + * @var int + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + * + * @var int + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + * + * @var int + */ + const STOP_CRITICAL = 2; + + /** + * The SMTP standard CRLF line break. + * If you want to change line break format, change static::$LE, not this. + */ + const CRLF = "\r\n"; + + /** + * "Folding White Space" a white space string used for line folding. + */ + const FWS = ' '; + + /** + * SMTP RFC standard line ending; Carriage Return, Line Feed. + * + * @var string + */ + protected static $LE = self::CRLF; + + /** + * The maximum line length supported by mail(). + * + * Background: mail() will sometimes corrupt messages + * with headers longer than 65 chars, see #818. + * + * @var int + */ + const MAIL_MAX_LINE_LENGTH = 63; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * The lower maximum line length allowed by RFC 2822 section 2.1.1. + * This length does NOT include the line break + * 76 means that lines will be 77 or 78 chars depending on whether + * the line break format is LF or CRLF; both are valid. + * + * @var int + */ + const STD_LINE_LENGTH = 76; + + /** + * Constructor. + * + * @param bool $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = null) + { + if (null !== $exceptions) { + $this->exceptions = (bool) $exceptions; + } + //Pick an appropriate debug output format automatically + $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html'); + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + $this->smtpClose(); + } + + /** + * Call mail() in a safe_mode-aware fashion. + * Also, unless sendmail_path points to sendmail (or something that + * claims to be sendmail), don't pass params (not a perfect fix, + * but it will do). + * + * @param string $to To + * @param string $subject Subject + * @param string $body Message Body + * @param string $header Additional Header(s) + * @param string|null $params Params + * + * @return bool + */ + private function mailPassthru($to, $subject, $body, $header, $params) + { + //Check overloading of mail function to avoid double-encoding + if ((int)ini_get('mbstring.func_overload') & 1) { + $subject = $this->secureHeader($subject); + } else { + $subject = $this->encodeHeader($this->secureHeader($subject)); + } + //Calling mail() with null params breaks + $this->edebug('Sending with mail()'); + $this->edebug('Sendmail path: ' . ini_get('sendmail_path')); + $this->edebug("Envelope sender: {$this->Sender}"); + $this->edebug("To: {$to}"); + $this->edebug("Subject: {$subject}"); + $this->edebug("Headers: {$header}"); + if (!$this->UseSendmailOptions || null === $params) { + $result = @mail($to, $subject, $body, $header); + } else { + $this->edebug("Additional params: {$params}"); + $result = @mail($to, $subject, $body, $header, $params); + } + $this->edebug('Result: ' . ($result ? 'true' : 'false')); + return $result; + } + + /** + * Output debugging info via a user-defined method. + * Only generates output if debug output is enabled. + * + * @see PHPMailer::$Debugoutput + * @see PHPMailer::$SMTPDebug + * + * @param string $str + */ + protected function edebug($str) + { + if ($this->SMTPDebug <= 0) { + return; + } + //Is this a PSR-3 logger? + if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { + $this->Debugoutput->debug(rtrim($str, "\r\n")); + + return; + } + //Avoid clash with built-in function names + if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) { + call_user_func($this->Debugoutput, $str, $this->SMTPDebug); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + /** @noinspection ForgottenDebugOutputInspection */ + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "
      \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/m', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * + * @param bool $isHtml True for HTML mode + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = static::CONTENT_TYPE_TEXT_HTML; + } else { + $this->ContentType = static::CONTENT_TYPE_PLAINTEXT; + } + } + + /** + * Send messages using SMTP. + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'qmail')) { + $this->Sendmail = '/var/qmail/bin/qmail-inject'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'qmail'; + } + + /** + * Add a "To" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addAddress($address, $name = '') + { + return $this->addOrEnqueueAnAddress('to', $address, $name); + } + + /** + * Add a "CC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('cc', $address, $name); + } + + /** + * Add a "BCC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addBCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('bcc', $address, $name); + } + + /** + * Add a "Reply-To" address. + * + * @param string $address The email address to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addReplyTo($address, $name = '') + { + return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer + * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still + * be modified after calling this function), addition of such addresses is delayed until send(). + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'Reply-To' + * @param string $address The email address + * @param string $name An optional username associated with the address + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $pos = false; + if ($address !== null) { + $address = trim($address); + $pos = strrpos($address, '@'); + } + if (false === $pos) { + //At-sign is missing. + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if ($name !== null && is_string($name)) { + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + } else { + $name = ''; + } + $params = [$kind, $address, $name]; + //Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + //Domain is assumed to be whatever is after the last @ symbol in the address + if ($this->has8bitChars(substr($address, ++$pos))) { + if (static::idnSupported()) { + if ('Reply-To' !== $kind) { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + + return true; + } + } elseif (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; + + return true; + } + } + //We have an 8-bit domain, but we are missing the necessary extensions to support it + //Or we are already sending to this address + return false; + } + + //Immediately add standard addresses without IDN. + return call_user_func_array([$this, 'addAnAddress'], $params); + } + + /** + * Set the boundaries to use for delimiting MIME parts. + * If you override this, ensure you set all 3 boundaries to unique values. + * The default boundaries include a "=_" sequence which cannot occur in quoted-printable bodies, + * as suggested by https://www.rfc-editor.org/rfc/rfc2045#section-6.7 + * + * @return void + */ + public function setBoundaries() + { + $this->uniqueid = $this->generateId(); + $this->boundary[1] = 'b1=_' . $this->uniqueid; + $this->boundary[2] = 'b2=_' . $this->uniqueid; + $this->boundary[3] = 'b3=_' . $this->uniqueid; + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addAnAddress($kind, $address, $name = '') + { + if ( + self::$validator === 'php' && + ((bool) preg_match('/[\x80-\xFF]/', $address)) + ) { + //The caller has not altered the validator and is sending to an address + //with UTF-8, so assume that they want UTF-8 support instead of failing + $this->CharSet = self::CHARSET_UTF8; + self::$validator = 'eai'; + } + if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) { + $error_message = sprintf( + '%s: %s', + $this->lang('Invalid recipient kind'), + $kind + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if (!static::validateAddress($address)) { + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if ('Reply-To' !== $kind) { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + $this->{$kind}[] = [$address, $name]; + $this->all_recipients[strtolower($address)] = true; + + return true; + } + } elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = [$address, $name]; + + return true; + } + + return false; + } + + /** + * Parse and validate a string containing one or more RFC822-style comma-separated email addresses + * of the form "display name
      " into an array of name/address pairs. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Note that quotes in the name part are removed. + * + * @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + * + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * @param string $charset The charset to use when decoding the address list string. + * + * @return array + */ + public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591) + { + $addresses = []; + if ($useimap && function_exists('imap_rfc822_parse_adrlist')) { + //Use this built-in parser if it's available + $list = imap_rfc822_parse_adrlist($addrstr, ''); + // Clear any potential IMAP errors to get rid of notices being thrown at end of script. + imap_errors(); + foreach ($list as $address) { + if ( + '.SYNTAX-ERROR.' !== $address->host && + static::validateAddress($address->mailbox . '@' . $address->host) + ) { + //Decode the name part if it's present and encoded + if ( + property_exists($address, 'personal') && + //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled + defined('MB_CASE_UPPER') && + preg_match('/^=\?.*\?=$/s', $address->personal) + ) { + $origCharset = mb_internal_encoding(); + mb_internal_encoding($charset); + //Undo any RFC2047-encoded spaces-as-underscores + $address->personal = str_replace('_', '=20', $address->personal); + //Decode the name + $address->personal = mb_decode_mimeheader($address->personal); + mb_internal_encoding($origCharset); + } + + $addresses[] = [ + 'name' => (property_exists($address, 'personal') ? $address->personal : ''), + 'address' => $address->mailbox . '@' . $address->host, + ]; + } + } + } else { + //Use this simpler parser + $list = explode(',', $addrstr); + foreach ($list as $address) { + $address = trim($address); + //Is there a separate name part? + if (strpos($address, '<') === false) { + //No separate name, just use the whole thing + if (static::validateAddress($address)) { + $addresses[] = [ + 'name' => '', + 'address' => $address, + ]; + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + $name = trim($name); + if (static::validateAddress($email)) { + //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled + //If this name is encoded, decode it + if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) { + $origCharset = mb_internal_encoding(); + mb_internal_encoding($charset); + //Undo any RFC2047-encoded spaces-as-underscores + $name = str_replace('_', '=20', $name); + //Decode the name + $name = mb_decode_mimeheader($name); + mb_internal_encoding($origCharset); + } + $addresses[] = [ + //Remove any surrounding quotes and spaces from the name + 'name' => trim($name, '\'" '), + 'address' => $email, + ]; + } + } + } + } + + return $addresses; + } + + /** + * Set the From and FromName properties. + * + * @param string $address + * @param string $name + * @param bool $auto Whether to also set the Sender address, defaults to true + * + * @throws Exception + * + * @return bool + */ + public function setFrom($address, $name = '', $auto = true) + { + $address = trim((string)$address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + //Don't validate now addresses with IDN. Will be done in send(). + $pos = strrpos($address, '@'); + if ( + (false === $pos) + || ((!$this->has8bitChars(substr($address, ++$pos)) || !static::idnSupported()) + && !static::validateAddress($address)) + ) { + $error_message = sprintf( + '%s (From): %s', + $this->lang('invalid_address'), + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto && empty($this->Sender)) { + $this->Sender = $address; + } + + return true; + } + + /** + * Return the Message-ID header of the last email. + * Technically this is the value from the last time the headers were created, + * but it's also the message ID of the last sent message except in + * pathological cases. + * + * @return string + */ + public function getLastMessageID() + { + return $this->lastMessageID; + } + + /** + * Check that a string looks like an email address. + * Validation patterns supported: + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `eai` Use a pattern similar to the HTML5 spec for 'email' and to firefox, extended to support EAI (RFC6530). + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * + * ```php + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * ``` + * + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * + * @param string $address The email address to check + * @param string|callable $patternselect Which pattern to use + * + * @return bool + */ + public static function validateAddress($address, $patternselect = null) + { + if (null === $patternselect) { + $patternselect = static::$validator; + } + //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603 + if (is_callable($patternselect) && !is_string($patternselect)) { + return call_user_func($patternselect, $address); + } + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) { + return false; + } + switch ($patternselect) { + case 'pcre': //Kept for BC + case 'pcre8': + /* + * A more complex and more permissive version of the RFC5322 regex on which FILTER_VALIDATE_EMAIL + * is based. + * In addition to the addresses allowed by filter_var, also permits: + * * dotless domains: `a@b` + * * comments: `1234 @ local(blah) .machine .example` + * * quoted elements: `'"test blah"@example.org'` + * * numeric TLDs: `a@b.123` + * * unbracketed IPv4 literals: `a@192.168.0.1` + * * IPv6 literals: 'first.last@[IPv6:a1::]' + * Not all of these will necessarily work for sending! + * + * @copyright 2009-2010 Michael Rushton + * Feel free to use and redistribute this code. But please keep this copyright notice. + */ + return (bool) preg_match( + '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . + '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . + '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . + '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . + '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . + '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . + '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . + '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', + $address + ); + case 'html5': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * + * @see https://html.spec.whatwg.org/#e-mail-state-(type=email) + */ + return (bool) preg_match( + '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . + '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', + $address + ); + case 'eai': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type + * form input elements (as above), modified to accept Unicode email addresses. + * This is also more lenient than Firefox' html5 spec, in order to make the regex faster. + * 'eai' is an acronym for Email Address Internationalization. + * This validator is selected automatically if you attempt to use recipient addresses + * that contain Unicode characters in the local part. + * + * @see https://html.spec.whatwg.org/#e-mail-state-(type=email) + * @see https://en.wikipedia.org/wiki/International_email + */ + return (bool) preg_match( + '/^[-\p{L}\p{N}\p{M}.!#$%&\'*+\/=?^_`{|}~]+@[\p{L}\p{N}\p{M}](?:[\p{L}\p{N}\p{M}-]{0,61}' . + '[\p{L}\p{N}\p{M}])?(?:\.[\p{L}\p{N}\p{M}]' . + '(?:[-\p{L}\p{N}\p{M}]{0,61}[\p{L}\p{N}\p{M}])?)*$/usD', + $address + ); + case 'php': + default: + return filter_var($address, FILTER_VALIDATE_EMAIL) !== false; + } + } + + /** + * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the + * `intl` and `mbstring` PHP extensions. + * + * @return bool `true` if required functions for IDN support are present + */ + public static function idnSupported() + { + return function_exists('idn_to_ascii') && function_exists('mb_convert_encoding'); + } + + /** + * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. + * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. + * This function silently returns unmodified address if: + * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) + * - Conversion to punycode is impossible (e.g. required PHP functions are not available) + * or fails for any reason (e.g. domain contains characters not allowed in an IDN). + * + * @see PHPMailer::$CharSet + * + * @param string $address The email address to convert + * + * @return string The encoded address in ASCII form + */ + public function punyencodeAddress($address) + { + //Verify we have required functions, CharSet, and at-sign. + $pos = strrpos($address, '@'); + if ( + !empty($this->CharSet) && + false !== $pos && + static::idnSupported() + ) { + $domain = substr($address, ++$pos); + //Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) { + //Convert the domain from whatever charset it's in to UTF-8 + $domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet); + //Ignore IDE complaints about this line - method signature changed in PHP 5.4 + $errorcode = 0; + if (defined('INTL_IDNA_VARIANT_UTS46')) { + //Use the current punycode standard (appeared in PHP 7.2) + $punycode = idn_to_ascii( + $domain, + \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | + \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, + \INTL_IDNA_VARIANT_UTS46 + ); + } elseif (defined('INTL_IDNA_VARIANT_2003')) { + //Fall back to this old, deprecated/removed encoding + $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003); + } else { + //Fall back to a default we don't know about + $punycode = idn_to_ascii($domain, $errorcode); + } + if (false !== $punycode) { + return substr($address, 0, $pos) . $punycode; + } + } + } + + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * + * @throws Exception + * + * @return bool false on error - See the ErrorInfo property for details of the error + */ + public function send() + { + try { + if (!$this->preSend()) { + return false; + } + + return $this->postSend(); + } catch (Exception $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Prepare a message for sending. + * + * @throws Exception + * + * @return bool + */ + public function preSend() + { + if ( + 'smtp' === $this->Mailer + || ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0)) + ) { + //SMTP mandates RFC-compliant line endings + //and it's also used with mail() on Windows + static::setLE(self::CRLF); + } else { + //Maintain backward compatibility with legacy Linux command line mailers + static::setLE(PHP_EOL); + } + //Check for buggy PHP versions that add a header with an incorrect line break + if ( + 'mail' === $this->Mailer + && ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017) + || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103)) + && ini_get('mail.add_x_header') === '1' + && stripos(PHP_OS, 'WIN') === 0 + ) { + trigger_error($this->lang('buggy_php'), E_USER_WARNING); + } + + try { + $this->error_count = 0; //Reset errors + $this->mailHeader = ''; + + //The code below tries to support full use of Unicode, + //while remaining compatible with legacy SMTP servers to + //the greatest degree possible: If the message uses + //Unicode in the local parts of any addresses, it is sent + //using SMTPUTF8. If not, it it sent using + //punycode-encoded domains and plain SMTP. + if ( + static::CHARSET_UTF8 === strtolower($this->CharSet) && + ($this->anyAddressHasUnicodeLocalPart($this->RecipientsQueue) || + $this->anyAddressHasUnicodeLocalPart(array_keys($this->all_recipients)) || + $this->anyAddressHasUnicodeLocalPart($this->ReplyToQueue) || + $this->addressHasUnicodeLocalPart($this->From)) + ) { + $this->UseSMTPUTF8 = true; + } + //Dequeue recipient and Reply-To addresses with IDN + foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { + if (!$this->UseSMTPUTF8) { + $params[1] = $this->punyencodeAddress($params[1]); + } + call_user_func_array([$this, 'addAnAddress'], $params); + } + if (count($this->to) + count($this->cc) + count($this->bcc) < 1) { + throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL); + } + + //Validate From, Sender, and ConfirmReadingTo addresses + foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) { + if ($this->{$address_kind} === null) { + $this->{$address_kind} = ''; + continue; + } + $this->{$address_kind} = trim($this->{$address_kind}); + if (empty($this->{$address_kind})) { + continue; + } + $this->{$address_kind} = $this->punyencodeAddress($this->{$address_kind}); + if (!static::validateAddress($this->{$address_kind})) { + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $address_kind, + $this->{$address_kind} + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + } + + //Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE; + } + + $this->setMessageType(); + //Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty && empty($this->Body)) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + + //Trim subject consistently + $this->Subject = trim($this->Subject); + //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + $this->MIMEHeader = ''; + $this->MIMEBody = $this->createBody(); + //createBody may have added some headers, so retain them + $tempheaders = $this->MIMEHeader; + $this->MIMEHeader = $this->createHeader(); + $this->MIMEHeader .= $tempheaders; + + //To capture the complete message when using mail(), create + //an extra header list which createHeader() doesn't fold in + if ('mail' === $this->Mailer) { + if (count($this->to) > 0) { + $this->mailHeader .= $this->addrAppend('To', $this->to); + } else { + $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + $this->mailHeader .= $this->headerLine( + 'Subject', + $this->encodeHeader($this->secureHeader($this->Subject)) + ); + } + + //Sign with DKIM if enabled + if ( + !empty($this->DKIM_domain) + && !empty($this->DKIM_selector) + && (!empty($this->DKIM_private_string) + || (!empty($this->DKIM_private) + && static::isPermittedPath($this->DKIM_private) + && file_exists($this->DKIM_private) + ) + ) + ) { + $header_dkim = $this->DKIM_Add( + $this->MIMEHeader . $this->mailHeader, + $this->encodeHeader($this->secureHeader($this->Subject)), + $this->MIMEBody + ); + $this->MIMEHeader = static::stripTrailingWSP($this->MIMEHeader) . static::$LE . + static::normalizeBreaks($header_dkim) . static::$LE; + } + + return true; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Actually send a message via the selected mechanism. + * + * @throws Exception + * + * @return bool + */ + public function postSend() + { + try { + //Choose the mailer and send through it + switch ($this->Mailer) { + case 'sendmail': + case 'qmail': + return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); + case 'smtp': + return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); + case 'mail': + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + default: + $sendMethod = $this->Mailer . 'Send'; + if (method_exists($this, $sendMethod)) { + return $this->{$sendMethod}($this->MIMEHeader, $this->MIMEBody); + } + + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + } + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true && $this->smtp->connected()) { + $this->smtp->reset(); + } + if ($this->exceptions) { + throw $exc; + } + } + + return false; + } + + /** + * Send mail using the $Sendmail program. + * + * @see PHPMailer::$Sendmail + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function sendmailSend($header, $body) + { + if ($this->Mailer === 'qmail') { + $this->edebug('Sending with qmail'); + } else { + $this->edebug('Sending with sendmail'); + } + $header = static::stripTrailingWSP($header) . static::$LE . static::$LE; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html + //Example problem: https://www.drupal.org/node/1057954 + + //PHP 5.6 workaround + $sendmail_from_value = ini_get('sendmail_from'); + if (empty($this->Sender) && !empty($sendmail_from_value)) { + //PHP config has a sender address we can use + $this->Sender = ini_get('sendmail_from'); + } + //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) { + if ($this->Mailer === 'qmail') { + $sendmailFmt = '%s -f%s'; + } else { + $sendmailFmt = '%s -oi -f%s -t'; + } + } else { + //allow sendmail to choose a default envelope sender. It may + //seem preferable to force it to use the From header as with + //SMTP, but that introduces new problems (see + //), and + //it has historically worked this way. + $sendmailFmt = '%s -oi -t'; + } + + $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + $this->edebug('Sendmail path: ' . $this->Sendmail); + $this->edebug('Sendmail command: ' . $sendmail); + $this->edebug('Envelope sender: ' . $this->Sender); + $this->edebug("Headers: {$header}"); + + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + $this->edebug("To: {$toAddr}"); + fwrite($mail, 'To: ' . $toAddr . "\n"); + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet); + $this->doCallback( + ($result === 0), + [[$addrinfo['address'], $addrinfo['name']]], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + $this->edebug("Result: " . ($result === 0 ? 'true' : 'false')); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result === 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + $this->edebug("Result: " . ($result === 0 ? 'true' : 'false')); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + + return true; + } + + /** + * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * + * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report + * + * @param string $string The string to be validated + * + * @return bool + */ + protected static function isShellSafe($string) + { + //It's not possible to use shell commands safely (which includes the mail() function) without escapeshellarg, + //but some hosting providers disable it, creating a security problem that we don't want to have to deal with, + //so we don't. + if (!function_exists('escapeshellarg') || !function_exists('escapeshellcmd')) { + return false; + } + + if ( + escapeshellcmd($string) !== $string + || !in_array(escapeshellarg($string), ["'$string'", "\"$string\""]) + ) { + return false; + } + + $length = strlen($string); + + for ($i = 0; $i < $length; ++$i) { + $c = $string[$i]; + + //All other characters have a special meaning in at least one common shell, including = and +. + //Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + //Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** + * Check whether a file path is of a permitted type. + * Used to reject URLs and phar files from functions that access local file paths, + * such as addAttachment. + * + * @param string $path A relative or absolute path to a file + * + * @return bool + */ + protected static function isPermittedPath($path) + { + //Matches scheme definition from https://www.rfc-editor.org/rfc/rfc3986#section-3.1 + return !preg_match('#^[a-z][a-z\d+.-]*://#i', $path); + } + + /** + * Check whether a file path is safe, accessible, and readable. + * + * @param string $path A relative or absolute path to a file + * + * @return bool + */ + protected static function fileIsAccessible($path) + { + if (!static::isPermittedPath($path)) { + return false; + } + $readable = is_file($path); + //If not a UNC path (expected to start with \\), check read permission, see #2069 + if (strpos($path, '\\\\') !== 0) { + $readable = $readable && is_readable($path); + } + return $readable; + } + + /** + * Send mail using the PHP mail() function. + * + * @see https://www.php.net/manual/en/book.mail.php + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function mailSend($header, $body) + { + $header = static::stripTrailingWSP($header) . static::$LE . static::$LE; + + $toArr = []; + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = trim(implode(', ', $toArr)); + + //If there are no To-addresses (e.g. when sending only to BCC-addresses) + //the following should be added to get a correct DKIM-signature. + //Compare with $this->preSend() + if ($to === '') { + $to = 'undisclosed-recipients:;'; + } + + $params = null; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html + //Example problem: https://www.drupal.org/node/1057954 + //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + + //PHP 5.6 workaround + $sendmail_from_value = ini_get('sendmail_from'); + if (empty($this->Sender) && !empty($sendmail_from_value)) { + //PHP config has a sender address we can use + $this->Sender = ini_get('sendmail_from'); + } + if (!empty($this->Sender) && static::validateAddress($this->Sender)) { + if (self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + } + $result = false; + if ($this->SingleTo && count($toArr) > 1) { + foreach ($toArr as $toAddr) { + $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); + $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet); + $this->doCallback( + $result, + [[$addrinfo['address'], $addrinfo['name']]], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + } + } else { + $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); + $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if (!$result) { + throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL); + } + + return true; + } + + /** + * Get an instance to use for SMTP operations. + * Override this function to load your own SMTP implementation, + * or set one with setSMTPInstance. + * + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP(); + } + + return $this->smtp; + } + + /** + * Provide an instance to use for SMTP operations. + * + * @return SMTP + */ + public function setSMTPInstance(SMTP $smtp) + { + $this->smtp = $smtp; + + return $this->smtp; + } + + /** + * Provide SMTP XCLIENT attributes + * + * @param string $name Attribute name + * @param ?string $value Attribute value + * + * @return bool + */ + public function setSMTPXclientAttribute($name, $value) + { + if (!in_array($name, SMTP::$xclient_allowed_attributes)) { + return false; + } + if (isset($this->SMTPXClient[$name]) && $value === null) { + unset($this->SMTPXClient[$name]); + } elseif ($value !== null) { + $this->SMTPXClient[$name] = $value; + } + + return true; + } + + /** + * Get SMTP XCLIENT attributes + * + * @return array + */ + public function getSMTPXclientAttributes() + { + return $this->SMTPXClient; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * + * @see PHPMailer::setSMTPInstance() to use a different class. + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function smtpSend($header, $body) + { + $header = static::stripTrailingWSP($header) . static::$LE . static::$LE; + $bad_rcpt = []; + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + //If we have recipient addresses that need Unicode support, + //but the server doesn't support it, stop here + if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) { + throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL); + } + //Sender already validated in preSend() + if ('' === $this->Sender) { + $smtp_from = $this->From; + } else { + $smtp_from = $this->Sender; + } + if (count($this->SMTPXClient)) { + $this->smtp->xclient($this->SMTPXClient); + } + if (!$this->smtp->mail($smtp_from)) { + $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); + throw new Exception($this->ErrorInfo, self::STOP_CRITICAL); + } + + $callbacks = []; + //Attempt to send to all recipients + foreach ([$this->to, $this->cc, $this->bcc] as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0], $this->dsn)) { + $error = $this->smtp->getError(); + $bad_rcpt[] = ['to' => $to[0], 'error' => $error['detail']]; + $isSent = false; + } else { + $isSent = true; + } + + $callbacks[] = ['issent' => $isSent, 'to' => $to[0], 'name' => $to[1]]; + } + } + + //Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) { + throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + + $smtp_transaction_id = $this->smtp->getLastTransactionID(); + + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + + foreach ($callbacks as $cb) { + $this->doCallback( + $cb['issent'], + [[$cb['to'], $cb['name']]], + [], + [], + $this->Subject, + $body, + $this->From, + ['smtp_transaction_id' => $smtp_transaction_id] + ); + } + + //Create error message for any bad addresses + if (count($bad_rcpt) > 0) { + $errstr = ''; + foreach ($bad_rcpt as $bad) { + $errstr .= $bad['to'] . ': ' . $bad['error']; + } + throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE); + } + + return true; + } + + /** + * Initiate a connection to an SMTP server. + * Returns false if the operation failed. + * + * @param array $options An array of options compatible with stream_context_create() + * + * @throws Exception + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @return bool + */ + public function smtpConnect($options = null) + { + if (null === $this->smtp) { + $this->smtp = $this->getSMTPInstance(); + } + + //If no options are provided, use whatever is set in the instance + if (null === $options) { + $options = $this->SMTPOptions; + } + + //Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $this->smtp->setSMTPUTF8($this->UseSMTPUTF8); + if ($this->Host === null) { + $this->Host = 'localhost'; + } + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = []; + if ( + !preg_match( + '/^(?:(ssl|tls):\/\/)?(.+?)(?::(\d+))?$/', + trim($hostentry), + $hostinfo + ) + ) { + $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry)); + //Not a valid host entry + continue; + } + //$hostinfo[1]: optional ssl or tls prefix + //$hostinfo[2]: the hostname + //$hostinfo[3]: optional port number + //The host string prefix can temporarily override the current setting for SMTPSecure + //If it's not specified, the default value is used + + //Check the host name is a valid name or IP address before trying to use it + if (!static::isValidHost($hostinfo[2])) { + $this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]); + continue; + } + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = (static::ENCRYPTION_STARTTLS === $this->SMTPSecure); + if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; //Can't have SSL and TLS at the same time + $secure = static::ENCRYPTION_SMTPS; + } elseif ('tls' === $hostinfo[1]) { + $tls = true; + //TLS doesn't use a prefix + $secure = static::ENCRYPTION_STARTTLS; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA256'); + if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[2]; + $port = $this->Port; + if ( + array_key_exists(3, $hostinfo) && + is_numeric($hostinfo[3]) && + $hostinfo[3] > 0 && + $hostinfo[3] < 65536 + ) { + $port = (int) $hostinfo[3]; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + //* it's not disabled + //* we are not connecting to localhost + //* we have openssl extension + //* we are not already using SSL + //* the server offers STARTTLS + if ( + $this->SMTPAutoTLS && + $this->Host !== 'localhost' && + $sslext && + $secure !== 'ssl' && + $this->smtp->getServerExt('STARTTLS') + ) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + $message = $this->getSmtpErrorMessage('connect_host'); + throw new Exception($message); + } + //We must resend EHLO after TLS negotiation + $this->smtp->hello($hello); + } + if ( + $this->SMTPAuth && !$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->oauth + ) + ) { + throw new Exception($this->lang('authenticate')); + } + + return true; + } catch (Exception $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + //We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + //If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + //As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions && null !== $lastexception) { + throw $lastexception; + } + if ($this->exceptions) { + // no exception was thrown, likely $this->smtp->connect() failed + $message = $this->getSmtpErrorMessage('connect_host'); + throw new Exception($message); + } + + return false; + } + + /** + * Close the active SMTP session if one exists. + */ + public function smtpClose() + { + if ((null !== $this->smtp) && $this->smtp->connected()) { + $this->smtp->quit(); + $this->smtp->close(); + } + } + + /** + * Set the language for error messages. + * The default language is English. + * + * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * Optionally, the language code can be enhanced with a 4-character + * script annotation and/or a 2-character country annotation. + * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * Do not set this from user input! + * + * @return bool Returns true if the requested language was loaded, false otherwise. + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + //Backwards compatibility for renamed language codes + $renamed_langcodes = [ + 'br' => 'pt_br', + 'cz' => 'cs', + 'dk' => 'da', + 'no' => 'nb', + 'se' => 'sv', + 'rs' => 'sr', + 'tg' => 'tl', + 'am' => 'hy', + ]; + + if (array_key_exists($langcode, $renamed_langcodes)) { + $langcode = $renamed_langcodes[$langcode]; + } + + //Define full set of translatable strings in English + $PHPMAILER_LANG = [ + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'buggy_php' => 'Your version of PHP is affected by a bug that may result in corrupted messages.' . + ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . + ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'data_not_accepted' => 'SMTP Error: data not accepted.', + 'empty_message' => 'Message body empty', + 'encoding' => 'Unknown encoding: ', + 'execute' => 'Could not execute: ', + 'extension_missing' => 'Extension missing: ', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'from_failed' => 'The following From address failed: ', + 'instantiate' => 'Could not instantiate mail function.', + 'invalid_address' => 'Invalid address: ', + 'invalid_header' => 'Invalid header name or value', + 'invalid_hostentry' => 'Invalid hostentry: ', + 'invalid_host' => 'Invalid host: ', + 'mailer_not_supported' => ' mailer is not supported.', + 'provide_address' => 'You must provide at least one recipient email address.', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'signing' => 'Signing Error: ', + 'smtp_code' => 'SMTP code: ', + 'smtp_code_ex' => 'Additional SMTP info: ', + 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_detail' => 'Detail: ', + 'smtp_error' => 'SMTP server error: ', + 'variable_set' => 'Cannot set or reset variable: ', + 'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses', + ]; + if (empty($lang_path)) { + //Calculate an absolute path so it can work if CWD is not here + $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; + } + + //Validate $langcode + $foundlang = true; + $langcode = strtolower($langcode); + if ( + !preg_match('/^(?P[a-z]{2})(?P + + + +
      + + getPageHeading(); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_Domdf.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_Domdf.php new file mode 100644 index 0000000000..aea4c96dca --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_Domdf.php @@ -0,0 +1,20 @@ +log('Hide grid lines'); +$spreadsheet->getActiveSheet()->setShowGridLines(false); + +$helper->log('Set orientation to landscape'); +$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE); + +$className = \PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf::class; +$helper->log("Write to PDF format using {$className}"); +IOFactory::registerWriter('Pdf', $className); + +// Save +$helper->write($spreadsheet, __FILE__, ['Pdf']); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_TCPDF.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_TCPDF.php new file mode 100644 index 0000000000..9a8593e1c8 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_TCPDF.php @@ -0,0 +1,20 @@ +log('Hide grid lines'); +$spreadsheet->getActiveSheet()->setShowGridLines(false); + +$helper->log('Set orientation to landscape'); +$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE); + +$className = \PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf::class; +$helper->log("Write to PDF format using {$className}"); +IOFactory::registerWriter('Pdf', $className); + +// Save +$helper->write($spreadsheet, __FILE__, ['Pdf']); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_mPDF.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_mPDF.php new file mode 100644 index 0000000000..b99c225092 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Pdf/21_Pdf_mPDF.php @@ -0,0 +1,20 @@ +log('Hide grid lines'); +$spreadsheet->getActiveSheet()->setShowGridLines(false); + +$helper->log('Set orientation to landscape'); +$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE); + +$className = \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf::class; +$helper->log("Write to PDF format using {$className}"); +IOFactory::registerWriter('Pdf', $className); + +// Save +$helper->write($spreadsheet, __FILE__, ['Pdf']); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/01_Simple_file_reader_using_IOFactory.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/01_Simple_file_reader_using_IOFactory.php new file mode 100644 index 0000000000..584fd5be81 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/01_Simple_file_reader_using_IOFactory.php @@ -0,0 +1,11 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory to identify the format'); +$spreadsheet = IOFactory::load($inputFileName); +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/02_Simple_file_reader_using_a_specified_reader.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/02_Simple_file_reader_using_a_specified_reader.php new file mode 100644 index 0000000000..9a705123e7 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/02_Simple_file_reader_using_a_specified_reader.php @@ -0,0 +1,13 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using ' . Xls::class); +$reader = new Xls(); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/03_Simple_file_reader_using_the_IOFactory_to_return_a_reader.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/03_Simple_file_reader_using_the_IOFactory_to_return_a_reader.php new file mode 100644 index 0000000000..305651de49 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/03_Simple_file_reader_using_the_IOFactory_to_return_a_reader.php @@ -0,0 +1,15 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/04_Simple_file_reader_using_the_IOFactory_to_identify_a_reader_to_use.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/04_Simple_file_reader_using_the_IOFactory_to_identify_a_reader_to_use.php new file mode 100644 index 0000000000..98aabfc651 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/04_Simple_file_reader_using_the_IOFactory_to_identify_a_reader_to_use.php @@ -0,0 +1,17 @@ +log('File ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' has been identified as an ' . $inputFileType . ' file'); + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with the identified reader type'); +$reader = IOFactory::createReader($inputFileType); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/05_Simple_file_reader_using_the_read_data_only_option.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/05_Simple_file_reader_using_the_read_data_only_option.php new file mode 100644 index 0000000000..d3ce9d8271 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/05_Simple_file_reader_using_the_read_data_only_option.php @@ -0,0 +1,17 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Turning Formatting off for Load'); +$reader->setReadDataOnly(true); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/06_Simple_file_reader_loading_all_worksheets.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/06_Simple_file_reader_loading_all_worksheets.php new file mode 100644 index 0000000000..5507c52b22 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/06_Simple_file_reader_loading_all_worksheets.php @@ -0,0 +1,20 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Loading all WorkSheets'); +$reader->setLoadAllSheets(); +$spreadsheet = $reader->load($inputFileName); + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log($sheetIndex . ' -> ' . $loadedSheetName); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/07_Simple_file_reader_loading_a_single_named_worksheet.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/07_Simple_file_reader_loading_a_single_named_worksheet.php new file mode 100644 index 0000000000..142a17f81c --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/07_Simple_file_reader_loading_a_single_named_worksheet.php @@ -0,0 +1,21 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Loading Sheet "' . $sheetname . '" only'); +$reader->setLoadSheetsOnly($sheetname); +$spreadsheet = $reader->load($inputFileName); + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log($sheetIndex . ' -> ' . $loadedSheetName); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php new file mode 100644 index 0000000000..66efc3e0fb --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php @@ -0,0 +1,21 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Loading Sheet' . ((count($sheetnames) == 1) ? '' : 's') . ' "' . implode('" and "', $sheetnames) . '" only'); +$reader->setLoadSheetsOnly($sheetnames); +$spreadsheet = $reader->load($inputFileName); + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log($sheetIndex . ' -> ' . $loadedSheetName); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/09_Simple_file_reader_using_a_read_filter.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/09_Simple_file_reader_using_a_read_filter.php new file mode 100644 index 0000000000..6e0eda14b7 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/09_Simple_file_reader_using_a_read_filter.php @@ -0,0 +1,40 @@ += 1 && $row <= 7) { + if (in_array($column, range('A', 'E'))) { + return true; + } + } + + return false; + } +} + +$filterSubset = new MyReadFilter(); + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Loading Sheet "' . $sheetname . '" only'); +$reader->setLoadSheetsOnly($sheetname); +$helper->log('Loading Sheet using filter'); +$reader->setReadFilter($filterSubset); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php new file mode 100644 index 0000000000..7b3fc440d1 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php @@ -0,0 +1,52 @@ +startRow = $startRow; + $this->endRow = $endRow; + $this->columns = $columns; + } + + public function readCell($column, $row, $worksheetName = '') + { + if ($row >= $this->startRow && $row <= $this->endRow) { + if (in_array($column, $this->columns)) { + return true; + } + } + + return false; + } +} + +$filterSubset = new MyReadFilter(9, 15, range('G', 'K')); + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); +$helper->log('Loading Sheet "' . $sheetname . '" only'); +$reader->setLoadSheetsOnly($sheetname); +$helper->log('Loading Sheet using configurable filter'); +$reader->setReadFilter($filterSubset); +$spreadsheet = $reader->load($inputFileName); + +$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); +var_dump($sheetData); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php new file mode 100644 index 0000000000..18562217b6 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php @@ -0,0 +1,64 @@ +startRow = $startRow; + $this->endRow = $startRow + $chunkSize; + } + + public function readCell($column, $row, $worksheetName = '') + { + // Only read the heading row, and the rows that were configured in the constructor + if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) { + return true; + } + + return false; + } +} + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +// Create a new Reader of the type defined in $inputFileType +$reader = IOFactory::createReader($inputFileType); + +// Define how many rows we want for each "chunk" +$chunkSize = 20; + +// Loop to read our worksheet in "chunk size" blocks +for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) { + $helper->log('Loading WorkSheet using configurable filter for headings row 1 and for rows ' . $startRow . ' to ' . ($startRow + $chunkSize - 1)); + // Create a new Instance of our Read Filter, passing in the limits on which rows we want to read + $chunkFilter = new ChunkReadFilter($startRow, $chunkSize); + // Tell the Reader that we want to use the new Read Filter that we've just Instantiated + $reader->setReadFilter($chunkFilter); + // Load only the rows that match our filter from $inputFileName to a PhpSpreadsheet Object + $spreadsheet = $reader->load($inputFileName); + + // Do some processing here + + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php new file mode 100644 index 0000000000..1f39ec4d30 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php @@ -0,0 +1,67 @@ +startRow = $startRow; + $this->endRow = $startRow + $chunkSize; + } + + public function readCell($column, $row, $worksheetName = '') + { + // Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow + if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) { + return true; + } + + return false; + } +} + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +// Create a new Reader of the type defined in $inputFileType +$reader = IOFactory::createReader($inputFileType); + +// Define how many rows we want to read for each "chunk" +$chunkSize = 20; +// Create a new Instance of our Read Filter +$chunkFilter = new ChunkReadFilter(); + +// Tell the Reader that we want to use the Read Filter that we've Instantiated +$reader->setReadFilter($chunkFilter); + +// Loop to read our worksheet in "chunk size" blocks +for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) { + $helper->log('Loading WorkSheet using configurable filter for headings row 1 and for rows ' . $startRow . ' to ' . ($startRow + $chunkSize - 1)); + // Tell the Read Filter, the limits on which rows we want to read this iteration + $chunkFilter->setRows($startRow, $chunkSize); + // Load only the rows that match our filter from $inputFileName to a PhpSpreadsheet Object + $spreadsheet = $reader->load($inputFileName); + + // Do some processing here + + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/13_Simple_file_reader_for_multiple_CSV_files.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/13_Simple_file_reader_for_multiple_CSV_files.php new file mode 100644 index 0000000000..d4817e304e --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/13_Simple_file_reader_for_multiple_CSV_files.php @@ -0,0 +1,29 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' into WorkSheet #1 using IOFactory with a defined reader type of ' . $inputFileType); +$spreadsheet = $reader->load($inputFileName); +$spreadsheet->getActiveSheet()->setTitle(pathinfo($inputFileName, PATHINFO_BASENAME)); +foreach ($inputFileNames as $sheet => $inputFileName) { + $helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' into WorkSheet #' . ($sheet + 2) . ' using IOFactory with a defined reader type of ' . $inputFileType); + $reader->setSheetIndex($sheet + 1); + $reader->loadIntoExisting($inputFileName, $spreadsheet); + $spreadsheet->getActiveSheet()->setTitle(pathinfo($inputFileName, PATHINFO_BASENAME)); +} + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ''); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php new file mode 100644 index 0000000000..efe6858270 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php @@ -0,0 +1,86 @@ +startRow = $startRow; + $this->endRow = $startRow + $chunkSize; + } + + public function readCell($column, $row, $worksheetName = '') + { + // Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow + if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) { + return true; + } + + return false; + } +} + +$helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +// Create a new Reader of the type defined in $inputFileType +$reader = IOFactory::createReader($inputFileType); + +// Define how many rows we want to read for each "chunk" +$chunkSize = 100; +// Create a new Instance of our Read Filter +$chunkFilter = new ChunkReadFilter(); + +// Tell the Reader that we want to use the Read Filter that we've Instantiated +// and that we want to store it in contiguous rows/columns +$reader->setReadFilter($chunkFilter) + ->setContiguous(true); + +// Instantiate a new PhpSpreadsheet object manually +$spreadsheet = new Spreadsheet(); + +// Set a sheet index +$sheet = 0; +// Loop to read our worksheet in "chunk size" blocks +/** $startRow is set to 2 initially because we always read the headings in row #1 * */ +for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) { + $helper->log('Loading WorkSheet #' . ($sheet + 1) . ' using configurable filter for headings row 1 and for rows ' . $startRow . ' to ' . ($startRow + $chunkSize - 1)); + // Tell the Read Filter, the limits on which rows we want to read this iteration + $chunkFilter->setRows($startRow, $chunkSize); + + // Increment the worksheet index pointer for the Reader + $reader->setSheetIndex($sheet); + // Load only the rows that match our filter into a new worksheet in the PhpSpreadsheet Object + $reader->loadIntoExisting($inputFileName, $spreadsheet); + // Set the worksheet title (to reference the "sheet" of data that we've loaded) + // and increment the sheet index as well + $spreadsheet->getActiveSheet()->setTitle('Country Data #' . (++$sheet)); +} + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ''); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, false, false, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/15_Simple_file_reader_for_tab_separated_value_file_using_the_Advanced_Value_Binder.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/15_Simple_file_reader_for_tab_separated_value_file_using_the_Advanced_Value_Binder.php new file mode 100644 index 0000000000..8213678a16 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/15_Simple_file_reader_for_tab_separated_value_file_using_the_Advanced_Value_Binder.php @@ -0,0 +1,41 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' into WorkSheet #1 using IOFactory with a defined reader type of ' . $inputFileType); +$reader->setDelimiter("\t"); +$spreadsheet = $reader->load($inputFileName); +$spreadsheet->getActiveSheet()->setTitle(pathinfo($inputFileName, PATHINFO_BASENAME)); + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ' (Formatted)'); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); + var_dump($sheetData); +} + +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ' (Unformatted)'); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, false, true); + var_dump($sheetData); +} + +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ' (Raw)'); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, false, false, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/16_Handling_loader_exceptions_using_TryCatch.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/16_Handling_loader_exceptions_using_TryCatch.php new file mode 100644 index 0000000000..80bb371d01 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/16_Handling_loader_exceptions_using_TryCatch.php @@ -0,0 +1,14 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory to identify the format'); + +try { + $spreadsheet = IOFactory::load($inputFileName); +} catch (InvalidArgumentException $e) { + $helper->log('Error loading file "' . pathinfo($inputFileName, PATHINFO_BASENAME) . '": ' . $e->getMessage()); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/17_Simple_file_reader_loading_several_named_worksheets.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/17_Simple_file_reader_loading_several_named_worksheets.php new file mode 100644 index 0000000000..db30bff8a4 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/17_Simple_file_reader_loading_several_named_worksheets.php @@ -0,0 +1,20 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); +$reader = IOFactory::createReader($inputFileType); + +// Read the list of Worksheet Names from the Workbook file +$helper->log('Read the list of Worksheets in the WorkBook'); +$worksheetNames = $reader->listWorksheetNames($inputFileName); + +$helper->log('There are ' . count($worksheetNames) . ' worksheet' . ((count($worksheetNames) == 1) ? '' : 's') . ' in the workbook'); +foreach ($worksheetNames as $worksheetName) { + $helper->log($worksheetName); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/18_Reading_list_of_worksheets_without_loading_entire_file.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/18_Reading_list_of_worksheets_without_loading_entire_file.php new file mode 100644 index 0000000000..bb58a2d58d --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/18_Reading_list_of_worksheets_without_loading_entire_file.php @@ -0,0 +1,20 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' information using IOFactory with a defined reader type of ' . $inputFileType); + +$reader = IOFactory::createReader($inputFileType); +$worksheetNames = $reader->listWorksheetNames($inputFileName); + +$helper->log('

      Worksheet Names

      '); +$helper->log('
        '); +foreach ($worksheetNames as $worksheetName) { + $helper->log('
      1. ' . $worksheetName . '
      2. '); +} +$helper->log('
      '); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/19_Reading_worksheet_information_without_loading_entire_file.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/19_Reading_worksheet_information_without_loading_entire_file.php new file mode 100644 index 0000000000..5cdc4988e0 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/19_Reading_worksheet_information_without_loading_entire_file.php @@ -0,0 +1,23 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' information using IOFactory with a defined reader type of ' . $inputFileType); + +$reader = IOFactory::createReader($inputFileType); +$worksheetData = $reader->listWorksheetInfo($inputFileName); + +$helper->log('

      Worksheet Information

      '); +$helper->log('
        '); +foreach ($worksheetData as $worksheet) { + $helper->log('
      1. ' . $worksheet['worksheetName']); + $helper->log('Rows: ' . $worksheet['totalRows'] . ' Columns: ' . $worksheet['totalColumns']); + $helper->log('Cell Range: A1:' . $worksheet['lastColumnLetter'] . $worksheet['totalRows']); + $helper->log('
      2. '); +} +$helper->log('
      '); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/20_Reader_worksheet_hyperlink_image.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/20_Reader_worksheet_hyperlink_image.php new file mode 100644 index 0000000000..9dad4b6c9b --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/20_Reader_worksheet_hyperlink_image.php @@ -0,0 +1,54 @@ +log('Start'); + +$spreadsheet = new Spreadsheet(); + +$aSheet = $spreadsheet->getActiveSheet(); + +$gdImage = @imagecreatetruecolor(120, 20); +$textColor = imagecolorallocate($gdImage, 255, 255, 255); +imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor); + +$baseUrl = 'https://phpspreadsheet.readthedocs.io'; + +$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing(); +$drawing->setName('In-Memory image 1'); +$drawing->setDescription('In-Memory image 1'); +$drawing->setCoordinates('A1'); +$drawing->setImageResource($gdImage); +$drawing->setRenderingFunction( + \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_JPEG +); +$drawing->setMimeType(\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_DEFAULT); +$drawing->setHeight(36); +$helper->log('Write image'); + +$hyperLink = new \PhpOffice\PhpSpreadsheet\Cell\Hyperlink($baseUrl, 'test image'); +$drawing->setHyperlink($hyperLink); +$helper->log('Write link: ' . $baseUrl); + +$drawing->setWorksheet($aSheet); + +$filename = tempnam(\PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir(), 'phpspreadsheet-test'); + +$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, $inputFileType); +$writer->save($filename); + +$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType); + +$reloadedSpreadsheet = $reader->load($filename); +unlink($filename); + +$helper->log('reloaded Spreadsheet'); + +foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $pDrawing) { + $helper->log('Read link: ' . $pDrawing->getHyperlink()->getUrl()); +} + +$helper->log('end'); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/21_Reader_CSV_Long_Integers_with_String_Value_Binder.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/21_Reader_CSV_Long_Integers_with_String_Value_Binder.php new file mode 100644 index 0000000000..2c80de3b32 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/21_Reader_CSV_Long_Integers_with_String_Value_Binder.php @@ -0,0 +1,27 @@ +log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' into WorkSheet #1 using IOFactory with a defined reader type of ' . $inputFileType); + +$spreadsheet = $reader->load($inputFileName); +$spreadsheet->getActiveSheet()->setTitle(pathinfo($inputFileName, PATHINFO_BASENAME)); + +$helper->log($spreadsheet->getSheetCount() . ' worksheet' . (($spreadsheet->getSheetCount() == 1) ? '' : 's') . ' loaded'); +$loadedSheetNames = $spreadsheet->getSheetNames(); +foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) { + $helper->log('Worksheet #' . $sheetIndex . ' -> ' . $loadedSheetName . ' (Formatted)'); + $spreadsheet->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); + var_dump($sheetData); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.csv b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.csv new file mode 100644 index 0000000000..b8cdf182f9 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.csv @@ -0,0 +1,4 @@ +First Name,Last Name,Nationality,Gender,Date of Birth,Time of Birth,Date/Time,PHP Coder,Sanity %Age +Mark,Baker,British,M,19-Dec-1960,01:30,=E2+F2,TRUE,32% +Toni,Baker,British,F,24-Nov-1950,20:00,=E3+F3,FALSE,95% +Rachel,Baker,British,F,7-Dec-1982,00:15,=E4+F4,FALSE,100% \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.tsv b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.tsv new file mode 100644 index 0000000000..35de47633b --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.tsv @@ -0,0 +1,4 @@ +First Name Last Name Nationality Gender Date of Birth Time of Birth Date/Time PHP Coder Sanity %Age +Mark Baker British M 19-Dec-1960 01:30 =E2+F2 TRUE 32% +Toni Baker British F 24-Nov-1950 20:00 =E3+F3 FALSE 95% +Rachel Baker British F 7-Dec-1982 00:15 =E4+F4 FALSE 100% \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.xls b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.xls new file mode 100644 index 0000000000..bd9bb110b9 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example1.xls differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.csv b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.csv new file mode 100644 index 0000000000..1750f1b612 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.csv @@ -0,0 +1,223 @@ +"City","Country","Latitude","Longitude" +"Kabul","Afghanistan",34.528455,69.171703 +"Tirane","Albania",41.33,19.82 +"Algiers","Algeria",36.752887,3.042048 +"Pago Pago","American Samoa",-14.27933,-170.700897 +"Andorra la Vella","Andorra",42.507531,1.521816 +"Luanda","Angola",-8.838333,13.234444 +"Buenos Aires","Argentina",-34.608417,-58.373161 +"Yerevan","Armenia",40.183333,44.516667 +"Oranjestad","Aruba",12.52458,-70.026459 +"Canberra","Australia",-35.3075,149.124417 +"Vienna","Austria",48.208333,16.373056 +"Baku","Azerbaijan",40.379571,49.891233 +"Nassau","Bahamas",25.06,-77.345 +"Manama","Bahrain",26.216667,50.583333 +"Dhaka","Bangladesh",23.709921,90.407143 +"Bridgetown","Barbados",13.096111,-59.608333 +"Minsk","Belarus",53.9,27.566667 +"Brussels","Belgium",50.846281,4.354727 +"Belmopan","Belize",17.251389,-88.766944 +"Thimphu","Bhutan",27.466667,89.641667 +"La Paz","Bolivia",-16.49901,-68.146248 +"Sarajevo","Bosnia and Herzegovina",43.8476,18.3564 +"Gaborone","Botswana",-24.65411,25.908739 +"Brasilia","Brazil",-15.780148,-47.92917 +"Road Town","British Virgin Islands",18.433333,-64.616667 +"Bandar Seri Begawan","Brunei Darussalam",4.9431,114.9425 +"Sofia","Bulgaria",42.697626,23.322284 +"Ouagadougou","Burkina Faso",12.364637,-1.533864 +"Bujumbura","Burundi",-3.361378,29.359878 +"Phnom Penh","Cambodia",11.55,104.916667 +"Yaounde","Cameroon",3.866667,11.516667 +"Ottawa","Canada",45.423494,-75.697933 +"Praia","Cape Verde",14.920833,-23.508333 +"George Town","Cayman Islands",19.286932,-81.367439 +"Bangui","Central African Republic",4.361698,18.555975 +"N'Djamena","Chad",12.104797,15.044506 +"Santiago","Chile",-33.42536,-70.566466 +"Beijing","China",39.904667,116.408198 +"Bogota","Colombia",4.647302,-74.096268 +"Moroni","Comoros",-11.717216,43.247315 +"Brazzaville","Congo",-4.266667,15.283333 +"San Jose","Costa Rica",9.933333,-84.083333 +"Yamoussoukro","Cote d'Ivoire",6.816667,-5.283333 +"Zagreb","Croatia",45.814912,15.978515 +"Havana","Cuba",23.133333,-82.366667 +"Nicosia","Cyprus",35.166667,33.366667 +"Prague","Czech Republic",50.087811,14.42046 +"Kinshasa","Congo",-4.325,15.322222 +"Copenhagen","Denmark",55.676294,12.568116 +"Djibouti","Djibouti",11.588,43.145 +"Roseau","Dominica",15.301389,-61.388333 +"Santo Domingo","Dominican Republic",18.5,-69.983333 +"Dili","East Timor",-8.566667,125.566667 +"Quito","Ecuador",-0.229498,-78.524277 +"Cairo","Egypt",30.064742,31.249509 +"San Salvador","El Salvador",13.69,-89.190003 +"Malabo","Equatorial Guinea",3.75,8.783333 +"Asmara","Eritrea",15.33236,38.92617 +"Tallinn","Estonia",59.438862,24.754472 +"Addis Ababa","Ethiopia",9.022736,38.746799 +"Stanley","Falkland Islands",-51.700981,-57.84919 +"Torshavn","Faroe Islands",62.017707,-6.771879 +"Suva","Fiji",-18.1416,178.4419 +"Helsinki","Finland",60.169813,24.93824 +"Paris","France",48.856667,2.350987 +"Cayenne","French Guiana",4.9227,-52.3269 +"Papeete","French Polynesia",-17.535021,-149.569595 +"Libreville","Gabon",0.390841,9.453644 +"Banjul","Gambia",13.453056,-16.5775 +"T'bilisi","Georgia",41.716667,44.783333 +"Berlin","Germany",52.523405,13.4114 +"Accra","Ghana",5.555717,-0.196306 +"Athens","Greece",37.97918,23.716647 +"Nuuk","Greenland",64.18362,-51.721407 +"Basse-Terre","Guadeloupe",15.998503,-61.72202 +"Guatemala","Guatemala",14.641389,-90.513056 +"St. Peter Port","Guernsey",49.458858,-2.534752 +"Conakry","Guinea",9.537029,-13.67847 +"Bissau","Guinea-Bissau",11.866667,-15.6 +"Georgetown","Guyana",6.804611,-58.154831 +"Port-au-Prince","Haiti",18.539269,-72.336408 +"Tegucigalpa","Honduras",14.082054,-87.206285 +"Budapest","Hungary",47.498406,19.040758 +"Reykjavik","Iceland",64.135338,-21.89521 +"New Delhi","India",28.635308,77.22496 +"Jakarta","Indonesia",-6.211544,106.845172 +"Tehran","Iran",35.696216,51.422945 +"Baghdad","Iraq",33.3157,44.3922 +"Dublin","Ireland",53.344104,-6.267494 +"Jerusalem","Israel",31.7857,35.2007 +"Rome","Italy",41.895466,12.482324 +"Kingston","Jamaica",17.992731,-76.792009 +"St. Helier","Jersey",49.190278,-2.108611 +"Amman","Jordan",31.956578,35.945695 +"Astana","Kazakhstan",51.10,71.30 +"Nairobi","Kenya",-01.17,36.48 +"Tarawa","Kiribati",01.30,173.00 +"Seoul","South Korea",37.31,126.58 +"Kuwait City","Kuwait",29.30,48.00 +"Bishkek","Kyrgyzstan",42.54,74.46 +"Riga","Latvia",56.53,24.08 +"Beirut","Lebanon",33.53,35.31 +"Maseru","Lesotho",-29.18,27.30 +"Monrovia","Liberia",06.18,-10.47 +"Vaduz","Liechtenstein",47.08,09.31 +"Vilnius","Lithuania",54.38,25.19 +"Luxembourg","Luxembourg",49.37,06.09 +"Antananarivo","Madagascar",-18.55,47.31 +"Lilongwe","Malawi",-14.00,33.48 +"Kuala Lumpur","Malaysia",03.09,101.41 +"Male","Maldives",04.00,73.28 +"Bamako","Mali",12.34,-07.55 +"Valletta","Malta",35.54,14.31 +"Fort-de-France","Martinique",14.36,-61.02 +"Nouakchott","Mauritania",-20.10,57.30 +"Mamoudzou","Mayotte",-12.48,45.14 +"Mexico City","Mexico",19.20,-99.10 +"Palikir","Micronesia",06.55,158.09 +"Chisinau","Moldova",47.02,28.50 +"Maputo","Mozambique",-25.58,32.32 +"Yangon","Myanmar",16.45,96.20 +"Windhoek","Namibia",-22.35,17.04 +"Kathmandu","Nepal",27.45,85.20 +"Amsterdam","Netherlands",52.23,04.54 +"Willemstad","Netherlands Antilles",12.05,-69.00 +"Noumea","New Caledonia",-22.17,166.30 +"Wellington","New Zealand",-41.19,174.46 +"Managua","Nicaragua",12.06,-86.20 +"Niamey","Niger",13.27,02.06 +"Abuja","Nigeria",09.05,07.32 +"Kingston","Norfolk Island",-45.20,168.43 +"Saipan","Northern Mariana Islands",15.12,145.45 +"Oslo","Norway",59.55,10.45 +"Masqat","Oman",23.37,58.36 +"Islamabad","Pakistan",33.40,73.10 +"Koror","Palau",07.20,134.28 +"Panama City","Panama",09.00,-79.25 +"Port Moresby","Papua New Guinea",-09.24,147.08 +"Asuncion","Paraguay",-25.10,-57.30 +"Lima","Peru",-12.00,-77.00 +"Manila","Philippines",14.40,121.03 +"Warsaw","Poland",52.13,21.00 +"Lisbon","Portugal",38.42,-09.10 +"San Juan","Puerto Rico",18.28,-66.07 +"Doha","Qatar",25.15,51.35 +"Bucuresti","Romania",44.27,26.10 +"Moskva","Russian Federation",55.45,37.35 +"Kigali","Rawanda",-01.59,30.04 +"Basseterre","Saint Kitts and Nevis",17.17,-62.43 +"Castries","Saint Lucia",14.02,-60.58 +"Saint-Pierre","Saint Pierre and Miquelon",46.46,-56.12 +"Apia","Samoa",-13.50,-171.50 +"San Marino","San Marino",43.55,12.30 +"Sao Tome","Sao Tome and Principe",00.10,06.39 +"Riyadh","Saudi Arabia",24.41,46.42 +"Dakar","Senegal",14.34,-17.29 +"Freetown","Sierra Leone",08.30,-13.17 +"Bratislava","Slovakia",48.10,17.07 +"Ljubljana","Slovenia",46.04,14.33 +"Honiara","Solomon Islands",-09.27,159.57 +"Mogadishu","Somalia",02.02,45.25 +"Pretoria","South Africa",-25.44,28.12 +"Madrid","Spain",40.25,-03.45 +"Khartoum","Sudan",15.31,32.35 +"Paramaribo","Suriname",05.50,-55.10 +"Mbabane","Swaziland",-26.18,31.06 +"Stockholm","Sweden",59.20,18.03 +"Bern","Switzerland",46.57,07.28 +"Damascus","Syrian Arab Republic",33.30,36.18 +"Dushanbe","Tajikistan",38.33,68.48 +"Bangkok","Thailand",13.45,100.35 +"Lome","Togo",06.09,01.20 +"Nuku'alofa","Tonga",-21.10,-174.00 +"Tunis","Tunisia",36.50,10.11 +"Ankara","Turkey",39.57,32.54 +"Ashgabat","Turkmenistan",38.00,57.50 +"Funafuti","Tuvalu",-08.31,179.13 +"Kampala","Uganda",00.20,32.30 +"Kiev","Ukraine",50.30,30.28 +"Abu Dhabi","United Arab Emirates",24.28,54.22 +"London","United Kingdom",51.36,-00.05 +"Dodoma","Tanzania",-06.08,35.45 +"Washington DC","United States of America",39.91,-77.02 +"Montevideo","Uruguay",-34.50,-56.11 +"Tashkent","Uzbekistan",41.20,69.10 +"Port-Vila","Vanuatu",-17.45,168.18 +"Caracas","Venezuela",10.30,-66.55 +"Hanoi","Viet Nam",21.05,105.55 +"Belgrade","Yugoslavia",44.50,20.37 +"Lusaka","Zambia",-15.28,28.16 +"Harare","Zimbabwe",-17.43,31.02 +"St. John's","Antigua and Barbuda",17.08,-61.50 +"Porto Novo","Benin",06.30,02.47 +"Hamilton","Bermuda"","32.18,-64.48 +"Avarua","Cook Islands",-21.12,-159.46 +"St. George's","Grenada",12.04,-61.44 +"Agaña","Guam",13.28,144.45 +"Victoria","Hong Kong",22.16,114.13 +"Tokyo","Japan",35.40,139.45 +"Pyongyang","North Korea",39.00,125.47 +"Vientiane","Laos",17.59,102.38 +"Tripoli","Libya",32.54,013.11 +"Skopje","Macedonia",42.00,021.28 +"Majuro","Marshall Islands",07.05,171.08 +"Port Louis","Mauritius",-20.10,57.30 +"Monaco","Monaco",43.44,007.25 +"Ulan Bator","Mongolia",47.54,106.52 +"Plymouth","Montserrat",16.44,-62.14 +"Rabat","Morocco",34.02,-06.51 +"Alofi","Niue",-14.27,-178.05 +"Saint-Denis","Réunion",-20.52,55.27 +"Victoria","Seychelles",-04.38,55.28 +"Singapore","Singapore",01.18,103.50 +"Colombo","Sri Lanka",06.55,79.52 +"Kingstown","St Vincent and the Grenadines",13.12,-61.14 +"Taipei","Taiwan",25.50,121.32 +"Port-of-Spain","Trinidad and Tobago",10.38,-61.31 +"Cockburn Harbour","Turks and Caicos Islands",21.30,-71.30 +"Charlotte Amalie","US Virgin Islands",18.22,-64.56 +"Vatican City","Vatican State",41.54,12.27 +"Laàyoune","Western Sahara",27.10,-13.11 +"San'a","Yemen",15.24,44.14 diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.xls b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.xls new file mode 100644 index 0000000000..dd213ab942 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/example2.xls differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/longIntegers.csv b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/longIntegers.csv new file mode 100644 index 0000000000..166f4a86d3 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reader/sampleData/longIntegers.csv @@ -0,0 +1,6 @@ +"Column 1","Column 2" +123456789012345678901234,234567890123456789012345 +345678901234567890123456,456789012345678901234567 +567890123456789012345678,678901234567890123456789 +789012345678901234567890,890123456789012345678901 +901234567890123456789012,012345678901234567890123 diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_properties.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_properties.php new file mode 100644 index 0000000000..1c222b5005 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_properties.php @@ -0,0 +1,53 @@ +load($inputFileName); + +// Read an array list of any custom properties for this document +$customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); + +// Loop through the list of custom properties +foreach ($customPropertyList as $customPropertyName) { + $helper->log('' . $customPropertyName . ': '); + // Retrieve the property value + $propertyValue = $spreadsheet->getProperties()->getCustomPropertyValue($customPropertyName); + // Retrieve the property type + $propertyType = $spreadsheet->getProperties()->getCustomPropertyType($customPropertyName); + + // Manipulate properties as appropriate for display purposes + switch ($propertyType) { + case 'i': // integer + $propertyType = 'integer number'; + + break; + case 'f': // float + $propertyType = 'floating point number'; + + break; + case 's': // string + $propertyType = 'string'; + + break; + case 'd': // date + $propertyValue = date('l, d<\s\up>S F Y g:i A', $propertyValue); + $propertyType = 'date'; + + break; + case 'b': // boolean + $propertyValue = ($propertyValue) ? 'TRUE' : 'FALSE'; + $propertyType = 'boolean'; + + break; + } + + $helper->log($propertyValue . ' (' . $propertyType . ')'); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_property_names.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_property_names.php new file mode 100644 index 0000000000..0f287f04f8 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Custom_property_names.php @@ -0,0 +1,20 @@ +load($inputFileName); + +// Read an array list of any custom properties for this document +$customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); + +foreach ($customPropertyList as $customPropertyName) { + $helper->log($customPropertyName); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Properties.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Properties.php new file mode 100644 index 0000000000..5bf25b8ef6 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Properties.php @@ -0,0 +1,64 @@ +load($inputFileName); + +// Read the document's creator property +$creator = $spreadsheet->getProperties()->getCreator(); +$helper->log('Document Creator: ' . $creator); + +// Read the Date when the workbook was created (as a PHP timestamp value) +$creationDatestamp = $spreadsheet->getProperties()->getCreated(); +// Format the date and time using the standard PHP date() function +$creationDate = date('l, d<\s\up>S F Y', $creationDatestamp); +$creationTime = date('g:i A', $creationDatestamp); +$helper->log('Created On: ' . $creationDate . ' at ' . $creationTime); + +// Read the name of the last person to modify this workbook +$modifiedBy = $spreadsheet->getProperties()->getLastModifiedBy(); +$helper->log('Last Modified By: ' . $modifiedBy); + +// Read the Date when the workbook was last modified (as a PHP timestamp value) +$modifiedDatestamp = $spreadsheet->getProperties()->getModified(); +// Format the date and time using the standard PHP date() function +$modifiedDate = date('l, d<\s\up>S F Y', $modifiedDatestamp); +$modifiedTime = date('g:i A', $modifiedDatestamp); +$helper->log('Last Modified On: ' . $modifiedDate . ' at ' . $modifiedTime); + +// Read the workbook title property +$workbookTitle = $spreadsheet->getProperties()->getTitle(); +$helper->log('Title: ' . $workbookTitle); + +// Read the workbook description property +$description = $spreadsheet->getProperties()->getDescription(); +$helper->log('Description: ' . $description); + +// Read the workbook subject property +$subject = $spreadsheet->getProperties()->getSubject(); +$helper->log('Subject: ' . $subject); + +// Read the workbook keywords property +$keywords = $spreadsheet->getProperties()->getKeywords(); +$helper->log('Keywords: ' . $keywords); + +// Read the workbook category property +$category = $spreadsheet->getProperties()->getCategory(); +$helper->log('Category: ' . $category); + +// Read the workbook company property +$company = $spreadsheet->getProperties()->getCompany(); +$helper->log('Company: ' . $company); + +// Read the workbook manager property +$manager = $spreadsheet->getProperties()->getManager(); +$helper->log('Manager: ' . $manager); +$s = new \PhpOffice\PhpSpreadsheet\Helper\Sample(); diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Worksheet_count_and_names.php b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Worksheet_count_and_names.php new file mode 100644 index 0000000000..630312b732 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/Worksheet_count_and_names.php @@ -0,0 +1,24 @@ +load($inputFileName); + +// Use the PhpSpreadsheet object's getSheetCount() method to get a count of the number of WorkSheets in the WorkBook +$sheetCount = $spreadsheet->getSheetCount(); +$helper->log('There ' . (($sheetCount == 1) ? 'is' : 'are') . ' ' . $sheetCount . ' WorkSheet' . (($sheetCount == 1) ? '' : 's') . ' in the WorkBook'); + +$helper->log('Reading the names of Worksheets in the WorkBook'); +// Use the PhpSpreadsheet object's getSheetNames() method to get an array listing the names/titles of the WorkSheets in the WorkBook +$sheetNames = $spreadsheet->getSheetNames(); +foreach ($sheetNames as $sheetIndex => $sheetName) { + $helper->log('WorkSheet #' . $sheetIndex . ' is named "' . $sheetName . '"'); +} diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xls b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xls new file mode 100644 index 0000000000..0db0efdcdb Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xls differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xlsx b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xlsx new file mode 100644 index 0000000000..2224dd4fe6 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example1.xlsx differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example2.xls b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example2.xls new file mode 100644 index 0000000000..18bfcf474a Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/Reading_workbook_data/sampleData/example2.xls differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/bootstrap.min.css b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/bootstrap.min.css new file mode 100644 index 0000000000..ed3905e0e0 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/font-awesome.min.css b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/font-awesome.min.css new file mode 100644 index 0000000000..4ec922351c --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.6.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/phpspreadsheet.css b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/phpspreadsheet.css new file mode 100644 index 0000000000..5ea3734260 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/css/phpspreadsheet.css @@ -0,0 +1,13 @@ +body { + padding-top: 20px; + padding-bottom: 20px; +} +.navbar { + margin-bottom: 20px; +} +.passed { + color: #339900; +} +.failed { + color: #ff0000; +} \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/FontAwesome.otf b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/FontAwesome.otf new file mode 100644 index 0000000000..d4de13e832 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/FontAwesome.otf differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.eot b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000..c7b00d2ba8 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.eot differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.svg b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000..8b66187fe0 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.svg @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.ttf b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000..f221e50a2e Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.ttf differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000..6e7483cf61 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff2 b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000..7eb74fd127 Binary files /dev/null and b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/fonts/fontawesome-webfont.woff2 differ diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/bootstrap.min.js b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/bootstrap.min.js new file mode 100644 index 0000000000..9bcd2fccae --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
      ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/jquery.min.js b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/jquery.min.js new file mode 100644 index 0000000000..f6a6a99e60 --- /dev/null +++ b/lib/vendor/phpoffice/phpspreadsheet/samples/bootstrap/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.1.0 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.1.0",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null!=a?a<0?this[a+this.length]:this[a]:f.call(this)},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"label"in b&&b.disabled===a||"form"in b&&b.disabled===a||"form"in b&&b.disabled===!1&&(b.isDisabled===a||b.isDisabled!==!a&&("label"in b||!ea(b))!==a)}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(_,aa),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=V.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(_,aa),$.test(j[0].type)&&qa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&sa(j),!a)return G.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||$.test(a)&&qa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){if(r.isFunction(b))return r.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return r.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(C.test(b))return r.filter(b,a,c);b=r.filter(b,a)}return r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType})}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/\S+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R),a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0, +r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,ja=/^$|\/(?:java|ecma)script/i,ka={option:[1,""],thead:[1,"","
      "],col:[2,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],_default:[0,"",""]};ka.optgroup=ka.option,ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead,ka.th=ka.td;function la(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function ma(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=la(l.appendChild(f),"script"),j&&ma(g),c){k=0;while(f=g[k++])ja.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var pa=d.documentElement,qa=/^key/,ra=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,sa=/^([^.]*)(?:\.(.+)|)/;function ta(){return!0}function ua(){return!1}function va(){try{return d.activeElement}catch(a){}}function wa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)wa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ua;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(pa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c-1:r.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h\x20\t\r\n\f]*)[^>]*)\/>/gi,ya=/\s*$/g;function Ca(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Da(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ea(a){var b=Aa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&za.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(m&&(e=oa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(la(e,"script"),Da),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=la(h),f=la(a),d=0,e=f.length;d0&&ma(g,!i&&la(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(la(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!ya.test(a)&&!ka[(ia.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function Xa(a,b,c,d,e){return new Xa.prototype.init(a,b,c,d,e)}r.Tween=Xa,Xa.prototype={constructor:Xa,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Xa.propHooks[this.prop];return a&&a.get?a.get(this):Xa.propHooks._default.get(this)},run:function(a){var b,c=Xa.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Xa.propHooks._default.set(this),this}},Xa.prototype.init.prototype=Xa.prototype,Xa.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Xa.propHooks.scrollTop=Xa.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Xa.prototype.init,r.fx.step={};var Ya,Za,$a=/^(?:toggle|show|hide)$/,_a=/queueHooks$/;function ab(){Za&&(a.requestAnimationFrame(ab),r.fx.tick())}function bb(){return a.setTimeout(function(){Ya=void 0}),Ya=r.now()}function cb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=aa[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function db(a,b,c){for(var d,e=(gb.tweeners[b]||[]).concat(gb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?hb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K); +if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),hb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ib[b]||r.find.attr;ib[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ib[g],ib[g]=e,e=null!=c(a,b,d)?g:null,ib[g]=f),e}});var jb=/^(?:input|select|textarea|button)$/i,kb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):jb.test(a.nodeName)||kb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});var lb=/[\t\r\n\f]/g;function mb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,mb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,mb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,mb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=mb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(c)+" ").replace(lb," ").indexOf(b)>-1)return!0;return!1}});var nb=/\r/g,ob=/[\x20\t\r\n\f]+/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(nb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:r.trim(r.text(a)).replace(ob," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type,g=f?null:[],h=f?e+1:d.length,i=e<0?h:f?e:0;i-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ha.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,""),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("